《JS 函数的执行时机》

99 阅读2分钟

代码1

let i 
for(i = 0; i<6; i++){
 setTimeout(()=>{   
 console.log(i)   
},0)
 }
 结果是打印出 666666

代码2

for(var i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
} 
结果是打印出 666666

代码3

for(let i = 0; i<6; i++){  
 setTimeout(()=>{    
 console.log(i) 
 },0) }
结果是打印出 012345
  • 规则:同步优先、异步靠边、回调垫底
  • js的执行机制: js是单线程环境,从上到下、依次执行,即 同步执行;在实例6中,for循环是同步代码,setTimeout是异步代码。js在执行代码的过程中,碰到同步代码会依次执行,碰到异步代码就会将其放入任务队列中进行等待,当同步代码执行完毕后再开始执行异步代码,即 异步执行。
  • js作用域问题:当同步代码执行完毕后,开始执行异步的setTimeout代码,执行setTimeout时需要从当前作用域内寻找一个变量i,此时for循环已执行完毕,当前 i=6,所以执行setTimeout时输出为6,任务队列中的剩余5个setTimeout也依次执行,输出为6。
  • 代码1中的let在for循环的外部。而在代码2中,let只在代码块内才有效,let只能声明一次。变量i是用let声明的,当前的i只在本轮循环中有效,每次循环的i 其实都是一个新的变量,所以setTimeout定时器里面的i,其实是不同的变量,即最后输出0-5。(若每次循环的变量i都是重新声明的,如何知道前一个循环的值?这是因为 JavaScript 引擎内部会记住前一个循环值)

上面代码1执行的结果是6个6,这里要说一下,当代码执行到setTimeout,setTimeout是一个定时器它会告诉计算机我会尽快执行,具体的时间不确定,也可以认为是在你for循环完毕我在执行,而在for循环执行完毕时此时的i=6然后再执行setTimeout后的代码,由于for循环了6次,也就是说定时器会执行6次,此时i=6,所以打印出6个6。

其他方式打印 0、1、2、3、4、5

for in

let arr=[‘a’,‘d’,‘e’,‘f’,‘g’,‘q’]
for(i in arr){
console.log(i)
}