これは、JavaScript 変数のスコープに関する一般的な問題です。新しい変数は、新しい実行コンテキストでのみ導入されるため、問題のあるコードでは、すべてのアクション コールバックi
で共有されます。
とにかく、標準的なイディオムに従って修正されたコードは次のとおりです。
function getNumber()
{
var items = [];
for (var i = 0; i < 5; i++) {
var num = i * 10;
items.push({
id: i, number: num,
// _i is a new variable for each callback
action: (function (_i) {
// use separate (one per callback) _i variable
return function () { alert(_i) }
})(i) // pass in current value for loop
});
}
return items
}
あるいは、すべてのネストが気に入らない場合は、「名前付き」関数を使用して同じタスクを実行しても問題ありません。指摘すべき重要な点は、クロージャーが新しい実行コンテキストから作成され (そしてそこから返され) 、別の変数がクローズオーバーされることです。
function getNumber()
{
function mkAction (i) {
return function () { alert(i) }
}
var items = [];
for (var i = 0; i < 5; i++) {
var num = i * 10;
items.push({
id: i, number: num,
action: mkAction(i)
});
}
return items
}
別のアプローチはFunction.bind
、ES5 から使用することです。
function getNumber()
{
var items = [];
for (var i = 0; i < 5; i++) {
var num = i * 10;
items.push({
id: i, number: num,
action: (function (_i) { alert(_i) }).bind(null, i)
});
}
return items
}
(Function.bind は、ネイティブ ブラウザーのサポートがなくても、新しい実行コンテキスト/クロージャーを使用してエミュレートできることに注意してください。MDC のドキュメントを参照してください。)
以下も参照してください。