函数的调用环境不同,时机不同,会导致最终的结果不同,看下面两端代码
//代码1
for(var i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
//打印出6,6,6,6,6,6
-------------------------------
//代码2
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
//打印出0,1,2,3,4,5
为什么结果会不同?
先来说var
var会在for循环中只有一个全局作用域,而setTimeout是一个回调函数,会创造出一个队列,意味着:等一下执行,所有需要执行的内容会放入这个队列,等执行完主线程的内容再挨个执行队列的内容。所以当运行到console时,i已经执行完for循环的i++,已经变成了6,所以打印出6个6。
再说说let
let除了会创建一个全局变量,还会在for循环中创建隐藏作用域,当循环一次时,i会在每个隐藏作用域中生成,当执行回调函数之后,i变成了0,1,2,3,4,5
再看一段代码
let i;
for(i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
//打印出6,6,6,6,6,6
此时let在外部定义了i,所以i并没有在for循环中生成隐藏作用域。
那么,有没有方法不用let来让i变成1,2,3,4,5呢?
答案是有的
for(var i=0;i<6;i++){
setTimeout((function(i){
return function(){
console.log(i)
}
})(i)
,0)
}
for (var i = 0; i <= 3; i++) {
(function (idx) {
setTimeout(function () {
console.log(idx);
}, 5);
})(i);
}
主要是将i当成一个参数传给内部的函数,避免外层迭代的影响