解决for循环使用setTimeout

442 阅读1分钟

1 解释为什么如下代码会打印 6 个 6

let i = 0
for(i = 0; i<6; i++){
  setTimeout(()=>{
    console.log(i)
  },0)
}

首先JS是单线程语言,每段代码的执行就像流水线一样,一步一步的流动下去。而setTimeout延时器的运行机制是会先将回调函数放到等待队列中,等待区域内其他主程序执行完毕后,按时间顺序先进先出执行回调函数。本质上是作用域的问题。 i的作用域是在全局,所以最后会连续输出6个6。

解决思路:人为给i创造作用域,保存记录i的值。

2 写出让上面代码打印 0、1、2、3、4、5 的方法

for(let i = 0; i<6; i++){
  setTimeout(()=>{
    console.log(i)
  },0)
}

按ES6的语法,let和for循环结合在一起,每次迭代的循环域内都会保存一个i的值,所以此次setTimeout()内匿名函数闭包的调用会获得当前迭代的值。

3 其他方法可以打印出 0、1、2、3、4、5

  1. 方案一 使用立即执行函数,人为提供一个i的闭包环境
for(var i = 0; i<6; i++){
    (function(j) {
        setTimeout( function timer() {
            console.log( j );
        }, 1000 );
    })(i);
}
  1. 将setTimeout的定义和调用分别放到不同部分
function timer(i) {
    setTimeout( console.log( i ), 1000 );
}
for (var i=0; i<6;i++) {
    timer(i);
}
  1. setTimeout传入第三个参数
function timer(i){ 
    console.log(i);   
 }

for (var i = 0; i < 6; i++) { 
    setTimeout(timer,1000,i); 
}