1

私はクロージャに懸命に取り組んでおり、ループ内で新しい関数がイテレータの最後の値を使用してクロージャを参照することを知っています

したがって、次の関数の結果は"item3 undefined"の 3 倍になります。

function buildList(list) {
  var result = [];
  for (var i = 0; i < list.length; i++) {
    var item = 'item' + list[i];
    result.push( function() {alert(item + ' ' + list[i])} );
  }
  return result;
}

function testList() {
  var fnlist = buildList([1,2,3]);
  // using j only to help prevent confusion - could use i
  for (var j = 0; j < fnlist.length; j++) {
    fnlist[j]();
  }
} 

そして、匿名関数がスコープを誘導できることを知っているので、最初の関数を次のように編集します。

function buildList(list) {
  var result = [];
  for (var i = 0; i < list.length; i++) {
    (function(){
      var item = 'item' + list[i];
      result.push( function() {alert(item + ' ' + list[i])} );

    })();
  }
  return result;
}

しかし、結果は「item1 undefined」、「item2 undefined」、「item3 undefined」、

私の質問は、なぜスコープを使用した後も結果がまだ定義されていないのですか?

4

3 に答える 3

0

iFunctionExpression によって導入された変数ではなく、親スコープにバインドされた変数を引き続き参照します。

正しい修正は、新しい変数を新しいスコープにバインドすることです

function buildList(list) {
  var result = [];
  for (var i = 0; i < list.length; i++) {
    (function(i){
      var item = 'item' + list[i];
      result.push( function() {alert(item + ' ' + list[i])} );

    })(i);
  }
  return result;
}

i関数に渡されていることに注意してください。

于 2013-11-11T08:13:45.370 に答える
0

i を無名関数に渡す必要があります。

function buildList(list) {
  var result = [];
  for (var i = 0; i < list.length; i++) {
    (function(i){
      var item = 'item' + list[i];
      result.push( function() {alert(item + ' ' + list[i])} );

    })(i);
  }
  return result;
}
于 2013-11-11T08:13:31.833 に答える
0

このコードの目的は学習のみであると仮定します。匿名関数を作成しますがi、以前のスコープでまだ参照しているため、最初に記述した最初のコードから何も変更しません。iまだ最後の値 ( list.length) があります。

これを回避するには、i作成した関数のスコープ内にの現在の値が必要です。

function buildList(list) {
  var result = [];

  for (var i = 0; i < list.length; i++) {
    var item = 'item' + list[i];
    result.push(function (index) { 
      return function() {alert(item + ' ' + list[index])}
    }(i));
  }

  return result;
}

または、 bindを使用して部分的に適用することもできます。

function buildList(list) {
  var result = [];

  for (var i = 0; i < list.length; i++) {
    var item = 'item' + list[i];
    result.push(function(index) {alert(item + ' ' + list[index])}.bind(null, i))
  }

  return result;
}

ES6、または JS 1.8.5 が有効になっている Firefox では、ブロック スコープ変数を宣言するletも使用できます。

function buildList(list) {
  var result = [];

  for (var i = 0; i < list.length; i++) {
    var item = 'item' + list[i];
    let index = i;
    result.push(() =>alert(item + ' ' + list[index]));
  }

  return result;
}

最後の例には、ES6 アロー関数もあります。

于 2013-11-11T08:22:36.070 に答える