for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
首先肯定的是,最后打印的结果不是0,1,2,3,4
最后的结果是5,5,5,5,5
因为 setTimeout 的 console.log(i); 的i是 var 定义的,所以是函数级的作用域,不属于 for 循环体,属于 global。等到 for 循环结束,i 已经等于 5 了,这个时候再执行 setTimeout 的五个回调函数(事件机制是单线程和事件队列),里面的 console.log(i); 的 i 去向上找作用域,只能找到 global下 的 i,即 5。所以输出都是 5。
如果 将上面循环中的var i 变成let i 就可以输出0,1,2,3,4.那这又是为什么
因为let的作用域是块,和var的作用域是不一样的,块作用域就可以保证每一次 for 循环,console.log(i); 都引用到 for 代码块作用域下的i,因为这样被引用,所以 for 循环结束后,这些作用域在 setTimeout 未执行前都不会被释放。
还有一种方式,需要我们人为的给console.log(i)创造作用域,
for (var i = 0; i < 5; i++) {
(function(i){ //立刻执行函数
setTimeout(function (){
console.log(i);
},1000);
})(i);
}
这里用到立刻执行函数。这样 console.log(i); 中的i就保存在每一次循环生成的立刻执行函数中的作用域里了