- 函数作用域
在js中,函数可以作为一个作用域来达到分隔变量的目的。
例如
var gv=1;
function func1(){
var lv=1;
console.log(lv);//1
console.log(gv);//1
}
func1();
//console.log(lv);//ReferenceError
console.log(gv);//1
- 块作用域
虽然在其他语言比如java,c等语言中有块作用域的概念,但是在js里面块并不能分隔变量。
例如
function fun1(arg1, arg2){
console.log(arg1);//10
console.log(arg2);//20
for(var i=0; i<1; i++){
var f1=10;
console.log(i);//0
for(var j=0; j<1; j++){
var f2=10;
console.log(j);//0
}
console.log(j+10);//11
}
console.log(f1);//10
console.log(f2);//10
console.log(i+10);//11
console.log(j+10);//11
if(true){
let l1=10;
for(let li1=0; li1<1; li1++){
}
console.log(l1);//10
}
console.log(l1);//ReferenceError
}
fun1(10,20);
我们可以看到在for循环中声明的变量在for循环之后的代码中都可以访问到,而let关键字声明的变量则控制在了块作用域中,let关键字是ES6中出现的关键字,能够让变量的作用域只在声明块中可用。
3. 变量声明的一些误区
先看一段代码
ga=4;
console.log(ga);
var gaa;
func1();
function func1(){
a=2;
console.log(a);
var a;
}
上面的代码运行结果是什么,java语言这样的代码是报错的;但是js不报错,原因就在于js编译器的处理方式。它会先把所有的声明在编译时完成,在执行时只要去作用域取变量就好了,所以上面的会变成如下形式的:
var gaa;
ga=4;
console.log(ga);
function func1(){
var a;
a=2;
console.log(a);
}
func1();
这里把所有的声明都提前声明好了,也就是把声明提升到了作用域开始的地方。
这里有一个比较重要的就是函数声明的调用,js中对函数的处理是函数优先的,也就是所有的函数声明会第一级被提升,变量是第二级。tip:如果是函数变量的声明则和变量是一样的
函数变量的写法可以是
var func1=function(){};
这里还有一个重要的点:当代码是这样的时候
func1();
var func1=function(){};
这时就会非常具有迷惑性,以为按照上面的说法这个是可以运行的;但是js编译器其实把上面的函数声明看成了两个部分,编译器会把它拆成两份进行处理
var func1;
func1=function(){};
完整的就是
var func1;
func1();
func1=function(){};
这里func1()并没有获得初始值,所以运行会报TypeError,但不是ReferenceError。变量的声明也是和函数声明处理是一样的
- 函数表达式
在一些js代码中可以看到一些特别不能理解的语句,比如
(function(){})();
(function(){}());
!function(){}();
+function(){}();
-function(){}();
这些都是函数表达式,简单地说就是js认为这是一段立即执行的代码而不是一个函数,因为在函数前面加了一个一元运算符,js会直接执行它,这样做的好处是这段执行的代码不会污染其他的代码。
5. 作用域闭包