for执行问题总结

for循环相关

for(var i = 1; i <= 5; i ++){
      console.log(i)  // 1 2 3 4 5
}

观察以下代码:

for(var i = 1; i <= 5; i ++){
    setTimeout(function timer(){
        console.log(i)  //5个 6
    }, 0)
}

问题描述:

为什么会全部输出6?如何改进,让它输出1,2,3,4,5?

原因:

因为setTimeout为宏任务,由于JS中单线程eventLoop机制,在主线程同步任务执行完后才去执行宏任务,因此循环结束后setTimeout中的回调才依次执行,但输出
i 的时候当前作用域没有,往上一级再找, 发现了 i ,此时循环已经结束,i 变成了6。因此会全部输出6。

解决方法:
1、利用IIFE(立即执行函数表达式)当每次for循环时,把此时的i变量传递到定时器中

for(var i = 1;i <= 5;i++){
    (function(j){
        setTimeout(function timer(){
        console.log(j)
        }, 0)
    })(i)
}

2、给定时器传入第三个参数, 作为timer函数的第一个函数参数

for(var i=1;i<=5;i++){
    setTimeout(function timer(j){
        console.log(j)
    }, 0, i)
}

3、使用ES6中的let

for(let i = 1; i <= 5; i++){
    setTimeout(function timer(){
        console.log(i)
    },0)
}

let使JS发生革命性的变化,让JS有函数作用域变为了块级作用域,用let后作用域链不复存在。代码的作用域以块级为单位,以上面代码为例:

// i = 1
{
    setTimeout(function timer(){
        console.log(1)
    },0)
}
// i = 2
{
    setTimeout(function timer(){
        console.log(2)
    },0)
}
// i = 3
...

因此能输出正确的结果1,2,3,4,5。

上一篇:for循环+setTimeout()引发变量作用域问题


下一篇:es6 bind(this) 方法