for、for-in 和 for-of 循​​环中变量的作用域规则不一致 [英] Inconsistent scope rules of variables in for, for-in and for-of loops

查看:21
本文介绍了for、for-in 和 for-of 循​​环中变量的作用域规则不一致的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我注意到我必须在 for 循环中使用 let,而不能使用 const.但是,我发现我可以在 for-infor-of 构造(下面的代码)中使用 const .凭直觉,我可以合理化这是因为 for 循环的实现方式不同/更原始,而另一个将 desugar 构造为 for 循环,其中迭代变量被分配在 for 循环的顶部.>

//不起作用for (const i = 0; i <3; i++) {控制台日志(i);}//作品for (让 i = 0; i <3; i++) {控制台日志(i);}//作品const object2 = ['a', 'b', 'c'];for (const v of object2) {控制台日志(v);}//作品const object3 = {一个:'一个',乙:'乙',c: 'c',};for (const v in object3) {控制台日志(v);}

我在 Mozilla MDN 上唯一能找到的关于此的内容是 for 循环页面:

<块引用>

这个表达式可以选择用 var 声明新变量关键词.这些变量不是循环的局部变量,即它们在for 循环所在的作用域相同.这个表达式的结果是丢弃.

这似乎也是错误的,因为如果我们为 i 使用 let 那么 ifor 之后不再在范围内 循环(与其他语言一致)

for (let i = 0; i <3; i++) {控制台日志(i);}//没有按预期工作控制台日志(i);

我的问题是这种行为是否在规范中的某个地方是预期的和定义的?MDN 对此没有多说.

解决方案

所以我注意到我必须在 for 循环中使用 let,而不能使用 const.

没有.您可以在 for 循环中使用 const 声明就好了.问题只是 const 声明了一个常量绑定,所以增量 i++const i 不起作用(它应该抛出一个异常,确保您处于严格模式).

一个如何使用const的例子:

for (const o = {index: 0, value: null}; o.index 

或者一个更有意义的地方:

for (const iterator = makeIterator(); !iterator.isDone(); iterator.next())doSomething(iterator.getCurrent());}

<块引用>

直觉上我可以合理化这是因为 for 循环的实现方式不同/更原始,而另一个构造 desugar 到 for 循环中,其中迭代变量被分配在 for 循环的顶部.

是的.在 for 循环中,您需要自己负责更新迭​​代变量.

  • for ([var] init; condition; update) {身体}

    变成

    [var] init;而(条件){身体;更新;}

  • for (const init; condition; update) {身体}

    变成

    <预>{const init;而(条件){身体;更新;}}

  • for (let init; condition; update) {身体}

    变得更复杂的事情

for ... infor ... of 循环中,您只需为生成的值声明一个赋值目标表达式.

  • for ([var]/let/const target of iterable) {身体}

    变成

    <预>{const _iterator = iterable[Symbol.iterator]();让 _result;while (!(_result = _iterator.next()).done) {[var]/let/const target = _result.value;身体;}}

  • for (... in enumerable)for (... of Reflect.enumerate(enumerable)) 一样.

<块引用>

我在 Mozilla MDN 上唯一能找到的关于此的内容是在 for 循环页面上,这似乎也是错误的.

是的,该部分似乎尚未针对 ES6 更新.

So I noticed that I have to use let inside a for loop, and cannot use const. However, I found that I can use const inside the for-in and for-of constructs (code below). 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.

// 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);
}

The only thing I could find on Mozilla MDN about this was on the for loop page:

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.

Which also seems wrong, because if we use a let for i then i is no longer in scope after the for loop (which is consistent with other languages)

for (let i = 0; i < 3; i++) {
  console.log(i);
}
// Doesn't work as expected
console.log(i);

My question is whether this behaviour is expected and defined in the spec somewhere? MDN doesn't say much about this.

解决方案

So I noticed that I have to use let inside a for loop, and cannot use const.

No. You can use a const declaration in a for loop just fine. The problem just is that const declares a constant binding, so an increment i++ doesn't work on const i (it should throw an exception, make sure you're in strict mode).

An example of how to use const:

for (const o = {index: 0, value: null}; o.index < arr.length; o.index++) {
    o.value = arr[o.index];
    doSomething(o);
}

Or one where it makes more sense:

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.

Yes. In a for loop, you need to take care of updating the iteration variables yourself.

  • for ([var] init; condition; update) {
        body
    }

    becomes

    [var] init;
    while (condition) {
        body;
        update;
    }

  • for (const init; condition; update) {
        body
    }

    becomes

    {
        const init;
        while (condition) {
            body;
            update;
        }
    }

  • for (let init; condition; update) {
        body
    }

    becomes something more complicated

In for … in and for … of loops, you just declare an assignment target expression for the produced value.

  • for ([var]/let/const target of iterable) {
        body
    }

    becomes

    {
        const _iterator = iterable[Symbol.iterator]();
        let _result;
        while (!(_result = _iterator.next()).done) {
            [var]/let/const target = _result.value;
            body;
        }
    }

  • for (… in enumerable) is just the same as 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.

Yes, looks like that section hasn't yet been updated for ES6.

这篇关于for、for-in 和 for-of 循​​环中变量的作用域规则不一致的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆