有如下代码:
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
讨论
也可以从变量作用域角度来分析。
第一种写法的函数调用时机是在整个函数运行之后,已经运行完后i为6,运行六次,因此结果为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)
}()
}
确实可以,然而只是一家之言,也可能只是瞎猫遇到死耗子。
相信随着我学习的深入对这个问题会有更深的理解。