クロージャーを含むループは、トリックを行う必要があります。
for (var i = 0; i <= 9; ++i) {
(function(i) { // Capture current value of 'i' in this scope.
shortcut.add(i.toString(), function() {
points = i || -1; // 'i' if 'i' is not 0, else -1.
sec = 0;
});
})(i);
}
次のコメントを更新します。では、なぜここで閉鎖が必要なのですか? で、最後(i);
はどういう意味ですか?
基本的に、渡された無名関数はshortcut.add()
すぐには呼び出されず、ループが終了した後で呼び出されるため、クロージャーが必要です。i
関数は、値ではなく参照によってキャプチャします。つまり、定義された時点ではなく、実行時にi
現在の値が表示されます。
したがって、shortcut.add()
ループ本体から直接呼び出すと、渡すすべての無名関数はi
、ループが終了した後にその値が current であることを確認することになり、常に同じになります ( 10
)。
各反復で新しい変数を作成すると、機能するように見えますが、機能しません。
for (var i = 0; i <= 9; ++i) {
var _i = i; // Create new variable containing current value of 'i'.
shortcut.add(i.toString(), function() {
points = _i || -1; // Won't work, '_i' is always 9.
sec = 0;
});
}
for
ループ本体は Javascript で独自のスコープを持たないため、_i
と同じように関数スコープで終了しi
、同じ方法でキャプチャされます (その最終値は、適用されないため、9
代わりに になります)。10
++i
したがって、ここで本当に必要なのは、反復ごとに新しいスコープです。これを実現するには、ループ内で関数を定義し、すぐに呼び出して、現在の値を渡しますi
。
var newScope = function(i) {
// Here, the value of 'i' will be the one current when 'newScope' is called
// and will not change, even if 'i' is captured by other functions.
};
newScope(i); // Call function with current value of 'i'.
最後に、呼び出し演算子を関数定義にnewScope
直接適用することで、名前を導入せずにそれを行うことができます。()
(function(i) {
// Here, the value of 'i' will be the one current when this function is
// called and will not change, even if 'i' is captured by other functions.
})(i); // Call function with current value of 'i'.
これがあなたの質問に適切に答えてくれることを願っています。そうでない場合は、お気軽にコメントを残してください。クロージャーの詳細については、 MDN の Closures を参照してください。