-1

これはおそらく簡単な質問ですが、夜遅く、これについて頭を悩ませることができません。

これが私のコードです

$(document).ready(function () {

var items = getNumber();

for (var i = 0; i < items.length; i++) {

    var test = items[i].action;
    test();

}

});

function getNumber()
{

var items = [];

for (var i = 0; i < 5; i++) {

    var num = i * 10;

    items.push({ id: i, number: num, action: function () { alert(i) } });
}


return items
}

アラート出力が常に 5 である理由を誰かに説明してもらえますか? 配列に追加された時点で、アラート パラメータをインデックスにしたいと考えています。ダイナミックに動いているようです。

また、これを機能させる方法を投稿していただければ、非常に感謝しています

4

1 に答える 1

4

これは、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 のドキュメントを参照してください。)

以下も参照してください。

于 2013-09-03T22:19:30.643 に答える