let i = 0
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
上面这段代码会打印 6 个 6。
这是因为每次 for 循环的时候,setTimeout 都执行一次,但是里面的函数没有被执行,而是被放到了任务队列里,等待执行。只有主线上的任务执行完,才会执行任务队列里的任务。当 for 循环结束后,此时 i 的值已经变成了6,这时回调函数按时间顺序先进先出执行。
要想实现打印结果为每次循环时的 i 值,即 0 1 2 3 4 5,可采用以下方案。
let 方案
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
JS 在 for 和 let 一起使用的时候,每次循环的时候多创建一个 i(复制当前循环中的 i),并把这个 i 给到定时器。所以主线程 for 循环执行完了,回调函数中的 i 是每次 for 循环时的 i。
闭包方案
for(var i = 0; i<6; i++){
!function(j){
setTimeout(()=>{
console.log(j)
},0)
}(i)
}
通过立即执行函数和闭包,将 i 的变量驻留在内存中,当输出 j 时,引用的是外部函数的变量值i,i的值是根据循环来的,执行 setTimeout 时已经确定了里面的输出。
setTimeout 附加参数方案
for(var i = 0; i<6; i++){
setTimeout((i)=>{
console.log(i)
},0,i)
}
附加参数,一旦定时器到期,它们会作为参数传递给回调函数。