彻底理解JavaScript for循环

346 阅读2分钟
var a = []
for (var i = 0; i < 10; i++) {
    a[i] = function () {
        console.log(i)
    }
}
a[5]() // 10

以上代码的执行顺序可以理解为

在循环中声明了function a[0-9],但是function a[0-9]并没有执行,当function a[0-9]执行的时候循环已经结束,并且已经++,所以当function a[0-9]执行的时候拿到的i是10,出现这样的原因便是因为for没有块级作用域,所以只能拿到全局变量 i

我们再看下面这种情况

for (var i = 0; i < 10; i++) {
    console.log(i)
}

// 0 1 2 3 4 5 6 7 8 9

诶,那我这里怎么又能是正常的呢,仔细看,其实

a[i] = function () {
    console.log(i)
}
console.log(i)

其实作为函数的内容他们都已经是被正确的执行了,只不过前面第一个例子执行的内容是声明了几个函数,而后面的例子执行的内容却是直接打印了i的内容。

那我们要如何去解决上面的问题呢

解决方案一

使用IFFE(匿名函数自执行)

将上面的代码进行修改

var a = []
for (var i = 0; i < 10; i++) {
    a[i] = (function (i) {
        return function () {
            console.log(i)
        }
    })(i)
}
a[5]() // 5

为什么这样子就可以正确执行呢,继续按照我们刚才的思路,可以理解成

a[0] = (function(0){
    return funtion(){
        console.log(0)  // 这里的0就是参数0
    }
})(0)   //循环第一次,执行循环中的内容

a[1] = (function(1){
    return funtion(){
        console.log(1)  // 这里的1就是参数1
    }
})(1)   //循环第二次,执行循环中的内容

所以当我执行a[5]时拿到的不再是for循环执行完毕后的 i(10),因为在我执行a[5]时我拿到的自执行函数的参数中的 i,我在循环中已经将每一个 i 已参数的形式传进了自执行函数中

解决方案二

es6 let块级作用域

var a = []
for (let i = 0; i < i; i++) {
    a[i] = function () {
        console.log(i)
    }
}
a[5]() // 5

同样为什么这样子也可以正确执行呢,我们继续分析代码的执行

{
    let i = 0;
    a[i] = function(){
        console.log(i)   // 1
    }
}  //循环第一次   

{
    let i = 1;
    a[i] = function(){
        console.log(i)   // 2
    }
}  //循环第二次

这样子相信大家就很容易理解了,这就是let创建块级作用域的作用域,每个i都只能在相应的作用域去拿到

以上也是个人的理解,如果有什么问题不对的也请纠正,请大家带着思考去看文章,不想被人说误人子弟吼吼吼