JS函数的调用时机

141 阅读1分钟

函数的调用环境不同,时机不同,会导致最终的结果不同,看下面两端代码

//代码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当成一个参数传给内部的函数,避免外层迭代的影响