for、for-in、for-of循环中变量作用域规则不一致
Inconsistent scope rules of variables in for, for-in and for-of loops
所以我注意到我必须在 for
循环中使用 let
,而不能使用 const
。但是,我发现我可以在 for-in
和 for-of
结构中使用 const
(下面的代码)。直觉上我可以合理化这是因为 for
循环实现 differently/is 更原始,而另一个构造 desugar 进入 for 循环,其中迭代变量被分配在 for 循环的顶部。
// Doesn't work
for (const i = 0; i < 3; i++) {
console.log(i);
}
// Works
for (let i = 0; i < 3; i++) {
console.log(i);
}
// Works
const object2 = ['a', 'b', 'c'];
for (const v of object2) {
console.log(v);
}
// Works
const object3 = {
a: 'a',
b: 'b',
c: 'c',
};
for (const v in object3) {
console.log(v);
}
我在 Mozilla MDN 上唯一能找到的关于此的内容是 for 循环页面:
This expression may optionally declare new variables with the var
keyword. These variables are not local to the loop, i.e. they are in
the same scope the for loop is in. The result of this expression is
discarded.
这似乎也是错误的,因为如果我们对 i
使用 let
那么 i
在 for
循环之后不再在范围内(这与其他语言)
for (let i = 0; i < 3; i++) {
console.log(i);
}
// Doesn't work as expected
console.log(i);
我的问题是这种行为是否在规范中的某个地方被预期和定义? MDN对此并没有多说。
是的。这确实是预期的行为。
const
定义了一个变量,顾名思义,它保持不变。这意味着 const 的值不能改变。
现在您在 for
循环中所做的是递增 "i",它被定义为一个常量。
for (const i = 0; i < 3; i++ /* <- this doesn't work */ ) {
console.log(i);
}
与 for .. in
或 for .. of
但是,您只需绑定变量即可。
换句话说:使用 for .. in/off
,变量在循环执行之前分配一次,而不是在每次迭代时分配一次。所以const
确实可以用
参考:
ForDeclaration : LetOrConst ForBinding
根据spec
ForDeclaration : LetOrConst ForBinding
let
和 const
允许在 for-in 和 for-of 中声明。
此外,根据 run-time 语义 spec
For each element name of the BoundNames of ForBinding do
这个表达式for (const v in object3) {
是每次迭代都执行并给出一个新的绑定。
然而,简单for-loop - for (const i = 0; i < 3; i++) {
,const i
只执行一次 因此它不允许你re-assign给它一个值。
你的第一个问题已经被@NullDev 回答了,所以我去第二个:
This expression may optionally declare new variables with the var
keyword. These variables are not local to the loop, i.e. they are in
the same scope the for loop is in. The result of this expression is
discarded.
"These variables are not local to the loop"表示var
关键字创建的计数器。如果您使用 let
那么计数器的范围仅在该 for 循环中。这是另一个预期的行为,因为 var
具有广泛的范围。是的,文档有点模棱两可。
So I noticed that I have to use let inside a for loop, and cannot use const.
没有。您可以在 for
循环中使用 const
声明就好了。问题只是 const
声明了一个常量绑定,所以增量 i++
对 const i
不起作用(它应该抛出异常,确保你处于严格模式)。
如何使用的示例 const
:
for (const o = {index: 0, value: null}; o.index < arr.length; o.index++) {
o.value = arr[o.index];
doSomething(o);
}
或者更有意义的一个:
for (const iterator = makeIterator(); !iterator.isDone(); iterator.next())
doSomething(iterator.getCurrent());
}
Intuitively I can rationalize that this is because the for loop is implemented differently/is more primitive, whereas the other constructs desugar into for loops where the iterating variable is assigned at the top of the for loop.
是的。在 for
循环中,您需要自己负责更新迭代变量。
for ([var] init; condition; update) {
body
}
成为
[var] init;
while (condition) {
body;
update;
}
for (const init; condition; update) {
body
}
变成
{
const init;
while (condition) {
body;
update;
}
}
for (let init; condition; update) {
body
}
变成
在 for … in
和 for … of
循环中,您只需为生成的值声明一个赋值目标表达式。
for ([var]/let/const target of iterable) {
body
}
变成
{
const _iterator = iterable[Symbol.iterator]();
let _result;
while (!(_result = _iterator.next()).done) {
[var]/let/const target = _result.value;
body;
}
}
for (… in enumerable)
等同于 for (… of Reflect.enumerate(enumerable))
.
The only thing I could find on Mozilla MDN about this was on the for
loop page, which also seems wrong.
是的,看起来该部分尚未针对 ES6 进行更新。
所以我注意到我必须在 for
循环中使用 let
,而不能使用 const
。但是,我发现我可以在 for-in
和 for-of
结构中使用 const
(下面的代码)。直觉上我可以合理化这是因为 for
循环实现 differently/is 更原始,而另一个构造 desugar 进入 for 循环,其中迭代变量被分配在 for 循环的顶部。
// Doesn't work
for (const i = 0; i < 3; i++) {
console.log(i);
}
// Works
for (let i = 0; i < 3; i++) {
console.log(i);
}
// Works
const object2 = ['a', 'b', 'c'];
for (const v of object2) {
console.log(v);
}
// Works
const object3 = {
a: 'a',
b: 'b',
c: 'c',
};
for (const v in object3) {
console.log(v);
}
我在 Mozilla MDN 上唯一能找到的关于此的内容是 for 循环页面:
This expression may optionally declare new variables with the var keyword. These variables are not local to the loop, i.e. they are in the same scope the for loop is in. The result of this expression is discarded.
这似乎也是错误的,因为如果我们对 i
使用 let
那么 i
在 for
循环之后不再在范围内(这与其他语言)
for (let i = 0; i < 3; i++) {
console.log(i);
}
// Doesn't work as expected
console.log(i);
我的问题是这种行为是否在规范中的某个地方被预期和定义? MDN对此并没有多说。
是的。这确实是预期的行为。
const
定义了一个变量,顾名思义,它保持不变。这意味着 const 的值不能改变。
现在您在 for
循环中所做的是递增 "i",它被定义为一个常量。
for (const i = 0; i < 3; i++ /* <- this doesn't work */ ) {
console.log(i);
}
与 for .. in
或 for .. of
但是,您只需绑定变量即可。
换句话说:使用 for .. in/off
,变量在循环执行之前分配一次,而不是在每次迭代时分配一次。所以const
确实可以用
参考:
ForDeclaration : LetOrConst ForBinding
根据spec
ForDeclaration : LetOrConst ForBinding
let
和 const
允许在 for-in 和 for-of 中声明。
此外,根据 run-time 语义 spec
For each element name of the BoundNames of ForBinding do
这个表达式for (const v in object3) {
是每次迭代都执行并给出一个新的绑定。
然而,简单for-loop - for (const i = 0; i < 3; i++) {
,const i
只执行一次 因此它不允许你re-assign给它一个值。
你的第一个问题已经被@NullDev 回答了,所以我去第二个:
This expression may optionally declare new variables with the var keyword. These variables are not local to the loop, i.e. they are in the same scope the for loop is in. The result of this expression is discarded.
"These variables are not local to the loop"表示var
关键字创建的计数器。如果您使用 let
那么计数器的范围仅在该 for 循环中。这是另一个预期的行为,因为 var
具有广泛的范围。是的,文档有点模棱两可。
So I noticed that I have to use let inside a for loop, and cannot use const.
没有。您可以在 for
循环中使用 const
声明就好了。问题只是 const
声明了一个常量绑定,所以增量 i++
对 const i
不起作用(它应该抛出异常,确保你处于严格模式)。
如何使用的示例 const
:
for (const o = {index: 0, value: null}; o.index < arr.length; o.index++) {
o.value = arr[o.index];
doSomething(o);
}
或者更有意义的一个:
for (const iterator = makeIterator(); !iterator.isDone(); iterator.next())
doSomething(iterator.getCurrent());
}
Intuitively I can rationalize that this is because the for loop is implemented differently/is more primitive, whereas the other constructs desugar into for loops where the iterating variable is assigned at the top of the for loop.
是的。在 for
循环中,您需要自己负责更新迭代变量。
for ([var] init; condition; update) { body }
成为[var] init; while (condition) { body; update; }
for (const init; condition; update) { body }
变成
{ const init; while (condition) { body; update; } }
for (let init; condition; update) { body }
变成
在 for … in
和 for … of
循环中,您只需为生成的值声明一个赋值目标表达式。
for ([var]/let/const target of iterable) { body }
变成
{ const _iterator = iterable[Symbol.iterator](); let _result; while (!(_result = _iterator.next()).done) { [var]/let/const target = _result.value; body; } }
for (… in enumerable)
等同于for (… of Reflect.enumerate(enumerable))
.
The only thing I could find on Mozilla MDN about this was on the
for
loop page, which also seems wrong.
是的,看起来该部分尚未针对 ES6 进行更新。