for (var i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i)
},1000)
} 会打印出5个6,这是why 因为 for 循环会先执行完(同步优先于异步优先于回调),这时五个 setTimeout 的回调全部塞入了事件队列中,然后 1 秒后一起执行了。
为什么不是 1 2 3 4 5 ,问题出在作用域上。 为 setTimeout 的 console.log(i); 的i是 var 定义的,所以是函数级的作用域,不属于 for 循环体,属于 global。
等到 for 循环结束,i 已经等于 5 了,这个时候再执行 setTimeout 的五个回调函数(参考上面对事件机制的阐述),里面的 console.log(i);
的 i 去向上找作用域,只能找到 global下 的 i,即 5。所以输出都是 5。 办法1:人为给 console.log(i); 创造作用域,保存i的值。for
(
var
i = 0; i < 5; i++) {
(
function
(i){
//立刻执行函数
setTimeout(
function
(){
console.log(i);
},1000);
})(i);
}
这里用到立刻执行函数。这样 console.log(i); 中的i就保存在每一次循环生成的立刻执行函数中的作用域里了。
办法2
for
(let i = 0; i < 5; i++) {
//let 代替 var
setTimeout(
function
(){
console.log(i);
},1000);
}
let 为代码块的作用域,所以每一次 for 循环,console.log(i); 都引用到 for 代码块作用域下的i,因为这样被引用,所以 for 循环结束后,这些作用域在 setTimeout 未执行前都不会被释放。