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引擎的运行
- 先把全局上下文压入栈中
- 再把for中的
setIimeout的环境压入栈中 - 再将
console.log(i)压入栈中 - 先执行后压出栈的语句,再弹出当前环境
- 然后再重复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