JS 函数的执行

79 阅读2分钟

JS 函数的执行

我在这里着重讲一下函数的运行原理。

调用栈

  • JS 引擎在调用一个函数前
  • 需要把函数所在的环境 push 到一个数组里
  • 等函数执行完毕的时候就弹出来(pop)
  • 最后返回到之前的环境

然后有一些语句并不是这样执行的

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

这个结果会打印的6个6,而不是0、1、2、3、4、5

为什么呢?

这个因为有消息队列的问题

按照Js引擎的运行

  1. 先把全局上下文压入栈中
  2. 再把for中的setIimeout的环境压入栈中
  3. 再将console.log(i)压入栈中
  4. 先执行后压出栈的语句,再弹出当前环境
  5. 然后再重复5次,第2~4步骤,共6次

正常来说,这样是对的,但是setTimeout是一个异步函数,在这里不执行

导致第二步这里,应该是再把for中的setIimeout的环境放进消息队列,先等待for循环执行6次,i=6时结束for循环,再从消息队列中一个一个拿出setIimeout来执行,重复步骤2~4

导致这里打印出的是,6个6而不是0、1、2、3、4、5

当然,如果你一定要以for循环setTimeout打印出0、1、2、3、4、5也不是没有办法 只需要把let放在for循环中

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

这样就可以打印出0、1、2、3、4、5

至于为什么会这样捏,主要是ES6对for循环中的let进行一些修改

  • 把每循环一次就把一个i都复制一份进入setTimeout中,使得console.log(i)i并不是后面循环结束后的i,这样才能打印出0、1、2、3、4、5