9.5 循环头中的 let
和 const
在以下循环头中允许声明变量:
for
for-in
for-of
声明一个变量,你可以使用 var
,let
或者 const
。每一种方式有不一样的效果,下面我将进行解释。
9.5.1 for
循环
在 for
循环头中使用 var
创建的变量只创建单个绑定(binding):
let arr = [];
for (var i=0; i < 3; i++) {
arr.push(() => i);
}
arr.map(x => x()); // [3,3,3]
在代码块中的三个箭头函数中的 i
都指向了同一个 binding,这就是为什么他们都返回相同的值。
如果你使用 let
声明变量,循环的每一次都会创建一个 binding :
let arr = [];
for (let i=0; i < 3; i++) {
arr.push(() => i);
}
arr.map(x => x()); // [0,1,2]
这一次,每个 i
指向一个循环体中的 binding 并且保持当时的值。因此,每个箭头函数都返回不同的值。
const
工作方式与 var
类似,但是不能改变 const
声明变量时初始化的值。
刚开始也许会觉得在每个循环中获取新的 binding 似乎很奇怪,但是当你使用循环创建指向循环变量的函数(例如事件处理的回调)时它非常有用。
for
循环:规范中的迭代绑定
The evaluation of thefor
循环 在第二例介绍var
并且在第三例介绍let/const
。 仅仅let
定义的变量被加到perIterationLets
列表(步骤 9), 作为传递给 ForBodyEvaluation() 的第一个之后的参数perIterationBindings
。
9.5.2 for-of
循环和 for-in
循环
In a for-of
loop, var
creates a single binding:
在 for-of
循环头中使用 var
创建的变量只创建单个绑定(binding):
let arr = [];
for (var i of [0, 1, 2]) {
arr.push(() => i);
}
arr.map(x => x()); // [2,2,2]
let
在循环的每一次都会创建一个 binding :
let arr = [];
for (let i of [0, 1, 2]) {
arr.push(() => i);
}
arr.map(x => x()); // [0,1,2]
const
也会在循环的每一次都会创建一个 binding ,但是创建的 bindings 是不可变的。
for-in
循环与 for-of
工作方式类似.
for-of
循环:规范中的迭代绑定
在 ForIn/OfBodyEvaluation 中介绍了for-of
的迭代绑定。 在步骤 5.b 中, 创建一个新的环境,并且绑定通过 BindingInstantiation 被增加。当前的迭代值存入变量nextValue
,并且在如下两种方式中用于初始化绑定:
- 定义单个变量(步骤 5.h.i): 通过 InitializeReferencedBinding
- 解构(步骤 5.i.iii):通过 BindingInitialization 中的一种 (ForDeclaration), 调用 BindingInitialization 的另一种 (BindingPattern)。