ECMAScript 6のlet
は、頭痛を引き起こすことなくブロックスコープを提供することになっています。以下のコードで、関数のi
が現在の反復の値ではなく、ループの最後の値(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
[〜#〜] mdn [〜#〜] によると、そのようなlet
ループでfor
を使用すると、ループ本体のスコープ内の変数がバインドされます。ブロック内で一時変数を使用すると、期待どおりに動作します。なぜそれが必要なのですか?
"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
Traceurとnode --harmony
を使用してスクリプトをテストしました。
squintの答えはもはや最新ではありません。 ECMA 6仕様 では、指定された動作は
for(let i;;){}
i
は、ループの反復ごとに新しいバインディングを取得します。
これは、すべてのクロージャーが異なるi
インスタンスをキャプチャすることを意味します。したがって、012
の結果は、現時点では正しい結果です。これをChrome v47 +で実行すると、正しい結果が得られます。IE11およびEdgeで実行すると、現在、誤った結果(333
)が生成されているようです。
このバグ/機能に関する詳細情報は、 このページ ;のリンクにあります。
let
式が使用されると、すべての反復が前のスコープまでチェーンされた新しいレキシカルスコープを作成するためです。これは、 here と報告されるlet
式の使用にパフォーマンスに影響します。
このコードを Babel に渡したので、使い慣れたES5の観点から動作を理解できます。
_for (let i = 0; i < 3; i++) {
i++;
things["fun" + i] = function() {
console.log(i);
};
i--;
}
_
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);
}
_
2つの変数が使用されていることがわかります。
外側のスコープのi
は、反復するにつれて変化する変数です。
内部スコープの__i
_は、各反復の一意の変数です。最終的には__i
_の3つの個別のインスタンスが存在します。
各コールバック関数は、対応する__i
_を参照でき、必要に応じて、他のスコープの__i
_ sとは無関係に操作することもできます。
(コールバック内でconsole.log(i++)
を実行すると、3つの異なる__i
_ sがあることを確認できます。以前のコールバックで__i
_を変更しても、後のコールバックからの出力には影響しません。)
各反復の終わりに、__i
_の値がi
にコピーされます。したがって、反復中に一意の内部変数を変更すると、外部反復変数に影響します。
ES6がWTFJSの長年の伝統を引き継いでいることは喜ばしいことです。
私見-最初にこのLETを実装したプログラマー(初期バージョンの結果を作成)は、正気に関して正しくそれを行いました。彼らはその実装中に仕様を一目見なかったかもしれません。
単一の変数が使用されているが、forループにスコープされていることはより意味があります。特に、ループ内の条件に応じてその変数を自由に変更できるためです。
しかし、待ってください-あなたはcanループ変数を変更します。 WTFJS !!ただし、内部スコープで変更しようとすると、今は動作しませんbecauseこれは新しい変数です。
私がしなければならないことが好きではない私が望むものを得るために(forに対してローカルな単一の変数):
{
let x = 0;
for (; x < length; x++)
{
things["fun" + x] = function() {
console.log(x);
};
}
}
反復ごとに新しい変数を処理するために、より直感的な(想像上の場合)バージョンを変更する場合:
for (let x = 0; x < length; x++)
{
let y = x;
things["fun" + y] = function() {
console.log(y);
};
}
Y変数を使用した私の意図が何であるかは明らかです。または、SANITYが宇宙を支配した場合はそうでした。
最初の例はFFで機能するようになりました。 0、1、2が生成されます。問題は修正されました。私はこの問題をWTFJSと呼びます。
追伸私のWTFJSへの言及は、上記のJoeyTwiddleからのものです。今日前に知っておくべきミームのように聞こえますが、今日はそれを学ぶ絶好の機会でした。