javascript for 循环中的 let 关键字

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16473350/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 04:49:35  来源:igfitidea点击:

let keyword in the for loop

javascriptecmascript-6

提问by Krzysztof Szafranek

ECMAScript 6's letis supposed to provide block scope without hoisting headaches. Can some explain why in the code below iin the function resolves to the last value from the loop (just like with var) instead of the value from the current iteration?

ECMAScript 6let应该提供块作用域而不会带来麻烦。有人可以解释为什么在下面的代码i中函数解析为循环中的最后一个值(就像 with var)而不是当前迭代中的值?

"use strict";
var things = {};
for (let i = 0; i < 3; i++) {
    things["fun" + i] = function() {
        console.log(i);
    };
}

things["fun0"](); // prints 3
things["fun1"](); // prints 3
things["fun2"](); // prints 3

According to MDNusing letin the forloop like that should bind the variable in the scope of the loop's body. Things work as I'd expect them when I use a temporary variable inside the block. Why is that necessary?

根据MDNletfor循环中使用,应该将变量绑定在循环体的范围内。当我在块内使用临时变量时,事情会像我期望的那样工作。为什么这是必要的?

"use strict";
var things = {};
for (let i = 0; i < 3; i++) {
    let index = i;
    things["fun" + i] = function() {
        console.log(index);
    };
}

things["fun0"](); // prints 0
things["fun1"](); // prints 1
things["fun2"](); // prints 2

I tested the script with Traceur and node --harmony.

我用 Traceur 和node --harmony.

回答by neuron

squint's answer is no longer up-to-date. In ECMA 6 specification, the specified behaviour is that in

眯眼的答案不再是最新的。在ECMA 6 规范中,指定的行为是

for(let i;;){}

igets a new binding for every iteration of the loop.

i为循环的每次迭代获取一个新的绑定。

This means that every closure captures a different iinstance. So the result of 012is the correct result as of now. When you run this in Chrome v47+, you get the correct result. When you run it in IE11 and Edge, currently the incorrect result (333) seems to be produced.

这意味着每个闭包都捕获不同的i实例。所以结果012是现在的正确结果。当您在 Chrome v47+ 中运行它时,您会得到正确的结果。当您在 IE11 和 Edge 中运行它时,目前333似乎产生了不正确的结果 ( )。

More information regarding this bug/feature can be found in the links in this page;

有关此错误/功能的更多信息可以在此页面的链接中找到

Since when the letexpression is used, every iteration creates a new lexical scope chained up to the previous scope. This has performance implications for using the letexpression, which is reported here.

因为当使用let表达式时,每次迭代都会创建一个新的词法作用域,链接到前一个作用域。这对使用let表达式的性能有影响,此处报告。

回答by joeytwiddle

I passed this code through Babelso we can understand the behaviour in terms of familiar ES5:

我通过Babel传递了这段代码,以便我们可以根据熟悉的 ES5 理解行为:

for (let i = 0; i < 3; i++) {
    i++;
    things["fun" + i] = function() {
        console.log(i);
    };
    i--;
}

Here is the code transpiled to ES5:

这是转译为 ES5 的代码:

var _loop = function _loop(_i) {
    _i++;
    things["fun" + _i] = function () {
        console.log(_i);
    };
    _i--;
    i = _i;
};

for (var i = 0; i < 3; i++) {
    _loop(i);
}

We can see that two variables are used.

我们可以看到使用了两个变量。

  • In the outer scope iis the variable that changes as we iterate.

  • In the inner scope _iis a unique variable for each iteration. There will eventually be three separate instances of _i.

    Each callback function can see its corresponding _i, and could even manipulate it if it wanted to, independently of the _is in other scopes.

    (You can confirm that there are three different _is by doing console.log(i++)inside the callback. Changing _iin an earlier callback does not affect the output from later callbacks.)

  • 在外部作用域中i是随着我们迭代而改变的变量。

  • 在内部作用域中_i,每次迭代都有一个唯一的变量。最终会有三个独立的_i.

    每个回调函数都可以看到其对应的_i,甚至可以根据需要对其进行操作,而与_i其他作用域中的s无关。

    (您可以_i通过console.log(i++)在回调内部执行来确认存在三个不同的s 。_i在较早的回调中更改不会影响以后回调的输出。)

At the end of each iteration, the value of _iis copied into i. Therefore changing the unique inner variable during the iterationwill affect the outer iterated variable.

在每次迭代结束时, 的值_i被复制到 中i。因此在迭代过程中改变唯一的内部变量会影响外部迭代变量。

It is good to see that ES6 has continued the long-standing tradition of WTFJS.

很高兴看到 ES6 延续了 WTFJS 的悠久传统。

回答by Gerard ONeill

IMHO -- the programmers who first implemented this LET (producing your initial version's results) did it correctly with respect to sanity; they may not have glanced at the spec during that implementation.

恕我直言——首先实现这个 LET(产生你的初始版本的结果)的程序员在理智方面做得正确;在实施过程中,他们可能没有看过规范。

It makes more sense that a single variable is being used, but scoped to the for loop. Especially since one should feel free to change that variable depending on conditions within the loop.

使用单个变量更有意义,但范围仅限于 for 循环。特别是因为人们可以根据循环内的条件随意更改该变量。

But wait -- you canchange the loop variable. WTFJS!! However, if you attempt to change it in your inner scope, it won't work now becauseit is a new variable.

但是等等——您可以更改循环变量。WTFJS!!但是,如果您尝试在内部范围内更改它,则它现在不起作用,因为它是一个新变量。

I don't like what I have to do To get what I want (a single variable that is local to the for):

我不喜欢我必须做的事情来获得我想要的东西(for 本地的单个变量):

{
    let x = 0;
    for (; x < length; x++)
    {
        things["fun" + x] = function() {
            console.log(x);
        };
    }
}

Where as to modify the more intuitive (if imaginary) version to handle a new variable per iteration:

至于修改更直观(如果是虚构的)版本以处理每次迭代的新变量:

for (let x = 0; x < length; x++)
{
    let y = x;
    things["fun" + y] = function() {
        console.log(y);
    };
}

It is crystal clear what my intention with the y variable is.. Or would have been if SANITY ruled the universe.

很清楚我对 y 变量的意图是什么......或者如果理智统治宇宙的话。

So your first example now works in FF; it produces the 0, 1, 2. You get to call the issue fixed. I call the issue WTFJS.

所以你的第一个例子现在适用于 FF;它产生 0, 1, 2。你可以称问题已修复。我称这个问题为 WTFJS。

ps. My reference to WTFJS is from JoeyTwiddle above; It sounds like a meme I should have known before today, but today was a great time to learn it.

附:我对 WTFJS 的引用来自上面的 JoeyTwiddle;这听起来像是我今天之前应该知道的模因,但今天是学习它的好时机。