1、问题:
- setTimeout是异步执行,即使setTimeout中的等待时间为0也不会立刻执行;
- for循环代码是同步,所以要等待for循环执行完以后才会执行setTimeout。
setTimeout运行机制的问题:定时函数被加入执行队列,等主程序运行完毕时,此时再调用定时函数,i的值已经变为4,四次的定时函数都会共用i=4这个值。
for(var i=0; i<4;i++){
setTimeout(function(){
console.log(i);
},100)
}
// 打印结果:4 4 4 4
2、解决:
(1)let
for循环头部的let不仅将i绑定到for循环中,它还将i重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。通过let声明块变量i,能作用于这个块。利用了let的块级作用域。
for(let i=0; i<4;i++){
setTimeout(function(){
console.log(i);
},100)
}
// 打印结果:0 1 2 3
(2)拆分结构
将setTimeout进行封装,此时定时函数的变量作用域就变为f函数代码块内,每次for循环传给定时器的i值都会变为定时函数的私有变量值,这样就达到了预期目的。
for(var i=0; i<4;i++){
f(i);
}
var f = function(i){
setTimeout(function(){
console.log(i);
},100)
}
// 打印结果:0 1 2 3
(3)闭包
通过闭包,将i的变量驻留在内存中,当输出j时,引用的是外部函数的变量值i,i的值是根据循环来的,执行setTimeout时已经确定了里面的的输出了。
for (var i = 0; i < 4; i++) {
(function (j) {
setTimeout(function () {
console.log(j);
}, 100)
})(i);
}
// 打印结果:0 1 2 3
(4)setTimeout第三个参数(可能解决不了)
由于每次传入的参数是从for循环里面取到的值,所以会依次输出