setTimeout 循环输出问题
解决 for 循环中 setTimeout 输出问题的三种方法
问题
改造下面的代码,让它正确输出 1, 2, 3, 4, 5:
for(var i = 1; i <= 5; i++){
setTimeout(function timer(){
console.log(i)
}, 0)
}
原代码会输出 5 个 6,因为 var 声明的变量没有块级作用域,所有定时器共享同一个 i 变量。
解答
方法一:使用 IIFE
通过立即执行函数创建独立作用域,每次循环时将当前的 i 值传入:
for(var i = 1; i <= 5; i++){
(function(j){
setTimeout(function timer(){
console.log(j)
}, 0)
})(i)
}
方法二:setTimeout 第三个参数
setTimeout 的第三个参数会作为回调函数的参数传入:
for(var i = 1; i <= 5; i++){
setTimeout(function timer(j){
console.log(j)
}, 0, i)
}
方法三:使用 let
let 声明具有块级作用域,每次循环都会创建新的变量:
for(let i = 1; i <= 5; i++){
setTimeout(function timer(){
console.log(i)
}, 0)
}
关键点
var声明的变量没有块级作用域,循环中的异步操作会共享同一个变量- IIFE 通过创建独立作用域来保存每次循环的变量值
setTimeout第三个参数可以向回调函数传递参数let声明具有块级作用域,是最简洁的解决方案
目录