setTimeout 在循环中的执行时机
分析 var 声明变量在 setTimeout 循环中的输出结果
问题
以下代码执行后会输出什么?
for(var i = 1; i <= 5; i++){
setTimeout(function timer(){
console.log(i)
}, 0)
}
解答
代码会输出 5 个 6。
执行过程:
for循环同步执行,创建 5 个setTimeout任务setTimeout是宏任务,会被放入任务队列等待执行- 循环结束时,
i的值已经变成 6 - 主线程空闲后,依次执行 5 个
setTimeout回调 - 每个回调执行时,访问的都是同一个变量
i,此时i已经是 6
解决方案 1:使用 let
for(let i = 1; i <= 5; i++){
setTimeout(function timer(){
console.log(i) // 输出 1 2 3 4 5
}, 0)
}
解决方案 2:使用闭包
for(var i = 1; i <= 5; i++){
(function(j){
setTimeout(function timer(){
console.log(j) // 输出 1 2 3 4 5
}, 0)
})(i)
}
关键点
setTimeout是宏任务,在主线程同步代码执行完后才执行var声明的变量没有块级作用域,循环中的i是同一个变量- 回调函数执行时通过作用域链查找
i,此时循环已结束,i为 6 - 使用
let可以创建块级作用域,每次循环都有独立的i - 使用闭包可以保存每次循环时
i的值
目录