JS函数的执行时机

288 阅读2分钟

有如下代码:


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

为何会打出6个6呢?

与函数的执行时机有关。setTimeout函数表示在执行函数之后马上进行打印操作。这时,for循环已经运行完毕,全局变量i的值变为6,由于setTimeout函数被执行了六次,因此会打出6个6

怎么让上述函数打印出0,1,2,3,4,5

由于let关键字声明的变量的作用域是块级作用域,因此可以考虑将变量声明到for循环中,这样函数每执行一次都会创建不同的i变量。 代码如下:



for(let i = 0; i<6; i++){         //将i变成局部变量
  setTimeout(()=>{
    console.log(i)
  },0)
}
//0,1,2,3,4,5

讨论

也可以从变量作用域角度来分析。
第一种写法的函数调用时机是在整个函数运行之后,已经运行完后i6,运行六次,因此结果为6个6

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

第二种写法,i是局部变量,每次运行完就会被打印出来,然后再次生成一个新的i。 验证如下:

for(let i = 0; i<6; i++){         //将i变成局部变量
  setTimeout(()=>{
    console.log(i)
  },0)
}
console.log(i)              
//Uncaught ReferenceError: i is not defined
//0
//1
//2
//3
//4
//5

第二种方法的i并不是全局变量,想要打印出i发现报错。

思考

既然使用局部变量可以解决这个问题,那么JS的立即执行函数是不是也可以应用到解决这个问题中呢?

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

确实可以,然而只是一家之言,也可能只是瞎猫遇到死耗子。
相信随着我学习的深入对这个问题会有更深的理解。