好玩的前端小知识
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任务队列进行执行打印任务。
而let不存在变量提升,对于每次for循环都是新的值。
解决方案:
- 闭包 - 通过闭包将变量i驻存在内存中,当时出j时,引用的是外部函数的变量i。
for (var i= 0; i< 3; i++) {
(function(j) {
setTimeout( function timer() {
console.log( j );
}, 0 );
})(i);
}
- 拆分结构
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)
}