前置知识

setTimeout(function,ms)

接受两个参数,第一个是回调函数,第二个是推迟执行的毫秒数
setTimeout()运行机制
必须要等到当前脚本的同步任务和“任务队列”中已有的事件 全部处理完以后,才会执行setTimeout()指定的任务

setTimeout(function,0)含义

运行下面代码,func1和func2谁会先执行?很明显func2先执行:

  1. setTimeout(function () {
  2. func1(); }, 0)
  3. func2();
  • setTimeout(f,0)将第二个参数设为0,作用是让f在现有的任务(脚本的同步任务和“任务队列”中已有的事件)一结束就立刻执行。也就是说,setTimeout(f,0)的作用是,尽可能早地执行指定的任务
  • setTimeout(f,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在”任务队列”的尾部添加一个事件,因此要等到同步任务和”任务队列”现有的事件都处理完,才会得到执行。

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

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

逻辑是:

  • 加了setTimeout()函数之后setTimeout会等到当前代码的for循环执行完了,再去执行console.log(i)

而for循环执行完之后,i已经是6了所以会打印出6个6

  • 因为只有一个 i , i 不小于 6 的时候才会退出循环,所以循环了6次,得到了6个6

    完整解释如下:

for 循环为同步执行,而 setTimeout 为异步执行,遇到上图同步异步混合的情况,会先从上往下执行同步代码,碰到异步的代码会将其插入到任务队列当中等待。 只有当for 循环任务同步执行完,才会执行任务队列里的任务 。也就是说等到 for 循环全部运行完毕后,才会执行 setTimeout ,执行 setTimeout 时需要从当前作用域内寻找一个变量 i ,此时for 循环已执行完毕,当前 i =6,所以执行 setTimeout 时输出为6,任务队列中的剩余5个 setTimeout 也依次执行,输出为6。

解决——for 和 let 配合有奇效 (面试考)

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

逻辑是:

  • for循环里声明变量的话,每次循环一次就创建一个i
  • 因为循环6次,创建了6个 i ,故 i 被分别赋值

关于setitmeout的通俗理解

你正在打游戏,还剩下最后一关,这时候你妈妈让你去吃饭,你嘴上说马上(对应setTimeout(function, 0)),但其实会把游戏打完之后再去吃饭

还可以使用结合const声明

  1. let i
  2. for(i = 0; i<6; i++){
  3. const x = i //在循环体中用const声明
  4. setTimeout(()=>{
  5. console.log(x)
  6. })
  7. } // 0 、1 、2 、3 、4 、5

注意
let 和const声明 都是作用在块内 { }
const 声明的同时必须赋值——区别于let声明