JS 函数的执行时机

91 阅读2分钟

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

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

这是因为循环先执行完,此时i=6,for循环停止并退出,只有1个i,再去打印出6次。 setTimeout就是尽快,但不是现在,而是忙完手头事情立即做的事

setTimeout函数用来指定某个函数或某段代码,在多少毫秒之后执行。它返回一个整数,表示定时器的编号;

setTimeout(func|code, delay)

setTimeout函数接受两个参数,第一个参数func|code是将要推迟执行的函数名或者一段代码,第二个参数delay是推迟执行的毫秒数,根据HTML5标准,delay最少是4毫秒。如果小于这个值,会被自动增加到4ms。

setTimeout(f,0)或写为setTimeout(()=>{},0),将第二个参数设为0,作用是让f在现有的任务(脚本的同步任务和“任务队列”中已有的事件)一结束就立刻执行。也就是说,setTimeout(f,0)的作用是,尽可能早地执行指定的任务。

setTimeout(function (){
  console.log("你好!");
}, 0);

上面代码的含义是,尽可能早地显示“你好!”。 setTimeout(f,0)指定的任务,最早也要到下一次Event Loop才会执行。

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

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

这是因为JS在for和let在一起用的时候,每次循环会多创建一个i,也就是把i复制了6遍。 变量i是let声明的,当前的i只是本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。JS引擎内部会记住上一轮循环的值,初始化本轮的 变量i时,就在上一轮循环的基础上进行计算,所以就算是for和setTimeout()执行的顺序不变,但是打印输出的还是本次循环i的值

3 除了使用 for let 配合,还有什么其他方法可以打印出 0、1、2、3、4、5

一种是利用setTimeout的第三个参数:

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

另外一种是利用闭包:

for (var i=0; i<6; i++){
   !(function(j){
       setTimeout(()=>{
         console.log(j)
       },0)
    })(i)   
}