为什么如下代码会打印 6 个 6
let i = 0
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
在解释为什么是 6 个 6 之前,先了解一下 setTimeout 函数的作用,举个形象点的栗子:
正当小明打游戏快推爆对面水晶的时候,他妈这时候叫他吃饭,这时候他先答应他妈马上去吃饭,接着又继续打一会直到游戏结束再去吃。这里的马上去就相当于 setTimeout 函数的机制,吃饭就是 console.log(i) ,但实际上还是先完成当前s手头上的事情(即 for 循环)之后,再尽快去吃饭。不过为什么会这样呢?这跟 JS 函数的执行机制有关, 要知道 setTimeout 是一个异步的函数,那么这段代码的执行就变成了,先走完整个循环,这时 i 已经变成了 6,才开始执行 6 个 console.log(i),所以最终只会打印出 6 个 6。
写出让上面代码打印 0、1、2、3、4、5 的方法
那有没有什么办法能够解决这个问题, 我就想这样,然后还要打印出 0 1 2 3 4 5 。
回答是有的,只需要稍稍改变一下就可以了。
只要把 let i = 0 放进 for 里面就可以实现了。这是JS为了迎合新手玩家而发明的方法。
for(let i = 0; i < 6; ++i) {
setTimeout(() => {
console.log(i)
}, 0)
}
那对上面的代码要怎么给出一个合理的解释呢
因为在 for 循环里用 let 声明 i 的话,每次执行 for 循环,其实都会创建一个新的 i(只是看不到),这个 i 会保留当前 i 的值,所以不管你过多久打印 i,当时的 i 已经被保存了下来,所以会依次打印出 0,1,2,3,4,5
除了使用 for let 配合,还有什么其他方法可以打印出 0、1、2、3、4、5
1. 可以通过自执行函数来实现
for (var i = 0; i <= 5; i++) {
!(function (j) {
setTimeout(function print() {
console.log(j);
}, 0);
})(i);
}
把 setTimeout 函数放在一个立即执行函数里面,这样立即执行函数就创建了一个新的作用域把 setTimeout 函数包裹了起来,并且用 j 捕获每次循环时的 i这样,打印出来的 i 就是每次循环时的 i。
2. 通过setTimeout第三个参数
for (var i = 0; i < 6; i++) {
setTimeout((i) => console.log(i), 0, i);
}