JS 函数的执行时机(for,let和setTimeout()的结合使用)
我们先来看下面一段代码A:
let i = 0
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
--------------输出结果----------------------------------------------------------------------
-> 6
-> 6
-> 6
-> 6
-> 6
-> 6
我们可以看到,输出结果是6个6。有些人可能会问,为什么不是0,1,2,3,4,5?
其原因就在于:函数里面的setTimeout。不知道这是什么的,可以看看这篇文章,关于setTimeout()你所不知道的地方,详解setTimeout()。
这里的setTimeout定时器会在循环结束后再执行里面的代码,循环结束后,i变为了6,而setTimeout被循环调用了6次,所以这时输出6个6。
接下来和let有关:
代码B:
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
--------------输出结果----------------------------------------------------------------------
-> 0
-> 1
-> 2
-> 3
-> 4
-> 5
我们可以看到这次的输出结果是0,1,2,3,4,5。
而代码改变的地方就只有一开始的i的声明定义放到了for循环里。为什么会变成这样了?可能你也看很出来了,原因在于let关键字。
首先,我们要知道let是什么?ES6简介 let 和 const 命令,该连接里面有let的详细介绍和用法。
接下来说原因:
在代码段B中,变量i是用let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以每一轮的输出结果是不一样的,分别是0,1,2,3,4,5。
你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值?这是因为 JS 引擎会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的结果上进行计算。所以就算是for和setTimeout()执行的顺序不变,但是打印输出的还是本次循环i的值。
不是有let,有没有其他办法也输出0,1,2,3,4,5?
当然是有的。
第一种:利用 setTimeout 的第三个参数
for(i = 0; i<6; i++){
setTimeout((i)=>{
console.log(i)
},0,i)
}
第二种:利用闭包
for(var i=0; i<6; i++) {
!(function(j) {
setTimeout(function(){
console.log(j)
}, 0)
})(i)
}
我的解释(可能不对):使用闭包,匿名函数里调用的i是外部的,只作用于本次循环,在外部的i因为循环继续增加,所以输出结果是0,1,2,3,4,5。