ES5中,没有块级作用域,所以会出现以下情况:
var callbacks = [];
for(var i=0;i<=2;i++){
callbacks[i] = function(){
return i * 2;
}
}
console.table([
callbacks[0](),
callbacks[1](),
callbacks[2](),
])
这段代码的结果是输出3个6。
首先var i=0这一句话,将i做了一个变量提升,i是一个跟callbacks平级的变量;
然后进行for循环,for 循环结束时,i的值已经被更新成为了3;
由于function(){return i*2}不是立即被调用的,而是循环结束后,也就是i等于3的时候才调用的,它执行的时候会去找它上一级作用域中i的值,发现i等于3,于是进行计算并输出,所以callbacks[0]()
,callbacks[1]()
,callbacks[2]()
的结果全部都是6。
ES6中我们可以用let来声明变量,将变量的作用域限定为块级作用域,不存在变量提升:
const callbacks = [];
for(let i=0;i<=2;i++){
callbacks[i] = function(){
return i * 2;
}
}
console.table([
callbacks[0](),
callbacks[1](),
callbacks[2](),
])
结果为0,2,4。
let声明的变量为块作用域,作用于当前块;每次循环都会把值保留下来供后面的闭包使用。
这段for循环等价于:
for (let i = 0; i < 10; i++) {
a[i] = (function(i) {
return function(){
console.log(i);
}
})(i);
}
在ES6中只需一个花括号就可以指定块作用域。
{
function foo(){
return 1;
}
console.log(foo() === 1);
{
function foo(){
return 2;
}
console.log(foo() === 2);
}
console.log(foo() === 1);
}
结果是打印3个true。
可见两个作用域没有相互影响,一对花括号就已经把作用域隔离。
网友评论