好玩的前端小知识

131 阅读1分钟

好玩的前端小知识

for(var i = 0;i<3;i++){   
   setTimeout(function(){   
       console.log(i)
   },0)
}
//3 3 3 
for(let i = 0;i<3;i++){   
   setTimeout(function(){   
       console.log(i)
   },0)
}
//0 1 2 

上述两种情况输出结果不同。原因如下:
首先,需要了解一下setTimeout延时器的运行机制。setTimeout会将回调函数放入到等待队列中,等待区域内其他主程序执行完成后,按照时间顺序进行‘先进先出’执行函数。

核心为作用域的问题。 setTimeout是异步执行,每次进入到for,setTimeout都会执行一次,此时,函数没有被执行而是被放到任务队列中,等待主线任务执行完毕后,才会执行任务队列的任务,也就是说,在for循环结束后,由于var存在变量提升,此时程序等同于

 var i;
 for(i = 0;i<3;i++){        
     setTimeout(function(){
     console.log(i)
     },0)
 }

此时i = 3,进入到setTimeout任务队列进行执行打印任务。

1646727095.jpg

而let不存在变量提升,对于每次for循环都是新的值。

解决方案:

  1. 闭包 - 通过闭包将变量i驻存在内存中,当时出j时,引用的是外部函数的变量i。
for (var i= 0; i< 3; i++) {
    (function(j) {
        setTimeout( function timer() {
            console.log( j );
        }, 0 );
    })(i);
}
  1. 拆分结构
function timer(i) {
    setTimeout( console.log( i ), 0);
}
for (var i= 0; i < 3;i++) {
    timer(i);
}

3.let - 方法同题目中相同

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