解除 for 循环时 var 和 let 定义变量的困惑

2,586 阅读2分钟

这个问题的产生以及应用场景就不多说了,基本每个人都会遇到,下面直接上代码。

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i); // i 指向全局的 i,也就是数组中函数所有的i都指向的是同一个变量i
  };
}
a[6](); // 10

上面代码中,变量i是var命令声明的,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会自增,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是循环结束之后i的值,也就是 10。

如果使用let,声明的变量仅在块级作用域内有效,最后输出的是 6。

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i); //由于 let 创建的变量是块级作用域的,所以在这个函数内每次都保存一个新的 i
  };
}
a[6](); // 6

这是因为let 创建的变量是块级作用域的,所以每次循环都是一个新的 i,每次的值都是 i++ 的结果。因为每次循环的 i 都是一个独立的变量(内存里的唯一地址),因此闭包记录的值都是唯一的,所以才能得到最终的结果

如果用 var 的话,变量 i 是一个全局变量,虽然循环体内每次都创建了一个函数来打印 i,但是当时当刻仅仅是一个指向全局变量 i 的指针,当循环结束之后无论你用哪一个下标去访问循环创建的闭包函数,打印的变量 i 都是全局的那一个,所以全部都是 10。