JS 函数的执行时机

140 阅读2分钟

一. 解释为什么如下代码会打印 6 个 6

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

答:

setTimeout的意思是马上做,是针对未来说的,马上做不等于现在做。 所以,这串代码会先执行for循环里i,循环6次后结束,然后执行(这时候i已经循环完了) console.log(i)6次,这时候i的值是6,console.log(i)就打印出来6个6。

下面是网友总结的for循环执行步骤:

  1. i赋值为0
  2. 判断i < 6 ?,满足进入第一循环
  3. setTimeout()会过一会执行–>跳过setTimeout()继续执行
  4. 执行i++,此时i的值为1
  5. 判断i < 6 ?,满足进入第二循环
  6. setTimeout()会过一会执行–>跳过setTimeout()继续执行
  7. 执行i++,此时i的值为2
  8. 省略…
  9. 执行i++,此时i的值为6
  10. 判断i < 6 ?,不满足跳出循环
  11. 执行第一次循环的setTimeout() //打印出a
  12. 执行第二次循环的setTimeout() //打印出a
  13. 执行第三次循环的setTimeout() //打印出a
  14. 执行第四次循环的setTimeout() //打印出a
  15. 执行第五次循环的setTimeout() //打印出a
  16. 执行第六次循环的setTimeout() //打印出a
  17. 结束 现在可以看出,由于setTimeout()的执行时间为for语句执行后,所以每次打印出的结果都为6

二. 写出让上面代码打印 0、1、2、3、4、5 的方法

for(let i = 0; i<6; i++){
    setTimeout(()=>{
        console.log(i)
    },0)
}
// 0 1 2 3 4 5

解释: 通过改变let i =0位置就发生了改变。因为let变量的作用域只能在当前函数中,所以每次for循环生成的都是一个新的i, setTimeout里输出的i就是这个新的i,这个i是不会变化的,所以输出的就是正常的。

三. 其他方法打印出 0、1、2、3、4、5

  • 闭包

这里加了一个函数外面的变量j

let i = 0
for(i = 0; i<6; i++){
  !function(j){
      setTimeout(()=>{
        console.log(j)
      },0)
  }(i)
}
  • 利用 setTimeout 的第三个参数
for (var i=0; i<6; ++i) {
	setTimeout(function(i){
		console.log(i)
	}, 0, i)
}