变量提升(Hoisting)被认为是, Javascript中执行上下文 (特别是创建和执行阶段)工作方式的一种认识。在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域。变量提升即将变量声明提升到它所在作用域的最开始的部分 。
如何理解变量提升?
我们习惯将 var a = 3
看做一条声明,
其实这是两条语句的简写:var a
和 a = 3
并且这两条语句是两个不同类型的语句,是由两个不同的组件完成的。
前一句是在编译阶段执行,后一句是在运行阶段执行。
所以,不管 var a
写在哪里,都会在代码本身被执行之前处理。这一过程很像是代码的一个移动过程,所以被大家称为“变量提升”。
例1:
console.log(a); // undefined
var a = '111';
console.log(a); // 111
实际运行过程:
var a;
console.log(a); // undefined
a = '111';
console.log(a); // 111
例2:
var a = [];
for(var i=0;i<3;i++){
a[i] = function(){
console.log(i);
}
}
a[0]();
a[1]();
a[2]();
//运行结果并不是0 1 2,而是3 3 3
实际运行过程:
var a = [];
var i; // 变量i在整个作用域下都是可以被访问到的,它不会被重新定义,
for(i=0;i<3;i++){ // 它的值只会在每次的迭代中不断地被改变,
a[i] = function(){ // 因为js是单线程,先执行完循环赋值才会继续往下,
console.log(i); // 当我们随后想通过函数调用打印它的值的时候,他实际上只有一个值,
} // 就是在最后一次循环赋给的那个值。
}
a[0]();
a[1]();
a[2]();
//运行结果 3 3 3
可以用立即执行函数解决: ( function(){…}) (实参) 或 ! function(){…}(实参)
var a = [];
for(var i=0;i<3;i++){
a[i] = (function(){
console.log(i);
})(i)
}
a[0]();
a[1]();
a[2]();
//运行结果:0 1 2