js中的变量提升(hoisting)
来看如下代码:
function HelloJS(){ var array = [1,2,3,4,5]; for(var i in array){ } alert(i); } HelloJS(); alert(i);
此段代码运行后先执行HelloJS();,会先输出4,然后再执行alert(i);,执行alert(i);时会报i is not defined的错误。
根据变量提升,这段代码等同于如下代码:
function HelloJS(){ var i; var array = [1,2,3,4,5]; for(i in array){ } alert(i); }
HelloJS();
alert(i);
可见对应变量i的声明自动提升到了代码块的头部这里即函数的头部,即第一个alert可以正常执行。
执行第二个alert(i)报错是因为:用var操作符定义的变量将成为定义该变量的作用域中的局部变量。也就是说如果在函数中使用var定义一个变量,那么这个变量在函数退出后就会被销毁。
JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)。(只会提升变量的声明语句,不会提升变量的赋值语句,例如var a = 1;只会提升var a;将它放到代码块的头部,而a=1;语句照样在原来的位置)
示例:
console.log(a);
var a =1;
以上语句并不会报错,只是提示undefined
。实际运行过程:
var a;
console.log(a);
a =1;
表示变量a已声明,但还未赋值。但是变量提升只对var命令声明的变量有效,如果一个变量不是用var命令声明的,就不会发生变量提升。
console.log(b);
b =1;
以上代码将会报错:ReferenceError: b is not defined
。
与普通变量一样,js里的function
也可看做变量,也存在变量提升情况:
abc();
function abc(){
console.log(1);
};
表面上,上面代码好像在声明之前就调用了函数abc
。但是实际上,由于“变量提升”,函数abc
定义部分被提升到了代码头部,也就是在调用之前已经声明了。但是,如果采用赋值语句定义函数,JavaScript就会报错:
abc();
var abc = function(){
console.log(1);
};
// TypeError: abc is not a function
因为,实际运行过程:
var abc;
abc();
abc = function(){
console.log(1);
};
这时候abc是个变量,并非function
。
函数声明可以被提前,如果是函数表达式则只有变量声明提前,函数体并不会提前。