21

onclickJavaScriptで動的に作成された「a」タグのイベントに関数を割り当てようとしています。すべてのタグは、次のようにループで作成されます。

for ( var i = 0; i < 4; i++ )
{
  var a = document.createElement( "a" );
  a.onclick = function( ) { alert( i ) };
  document.getElementById( "foo" ).appendChild( a );
}

4 つのリンクすべてのアラート値は常に「4」です。かなり明白。グーグルで検索すると、次のコード スニペットを示す投稿に出くわしました。

a.onclick = (function(p, d) {
return function(){ show_photo(p, d) }
})(path, description);

私は自分のニーズに合わせて微調整し、alert( i ) が正しく機能するようにしましたが、上記のコードが何をするかを正確に説明できる人がいれば幸いです。

4

3 に答える 3

46

関数をクリック ハンドラーに割り当てると、クロージャーが作成されます。

基本的に、関数をネストするとクロージャーが形成されます。内部関数は、親関数が既に実行された後でも、外側の囲み関数に存在する変数を参照できます。

クリック イベントが実行された時点で、ハンドラは変数が持っていた最後の値を参照しiます。これは、その変数がクロージャに格納されているためです。

お気づきのとおり、i変数を引数として受け入れるためにクリック ハンドラー関数をラップし、別の関数を返す (基本的には別のクロージャーを作成する) ことで、期待どおりに動作します。

for ( var i = 0; i < 4; i++ ) {
  var a = document.createElement( "a" );
  a.onclick = (function(j) { // a closure is created
    return function () {
      alert(j); 
    }
  }(i));
  document.getElementById( "foo" ).appendChild( a );
}

反復して実際に 4 つの関数を作成すると、各関数iは作成時の参照を格納し ( を渡すことによってi)、この値は外側のクロージャに格納され、クリック イベントが発生すると内側の関数が実行されます。

次のスニペットを使用して、クロージャー (およびカリーの非常に基本的な概念) を説明します。単純な例を使用すると、概念を理解しやすくなると思います。

// a function that generates functions to add two numbers
function addGenerator (x) { // closure that stores the first number
  return function (y){ // make the addition
    return x + y;
  };
}

var plusOne = addGenerator(1), // create two number adding functions
    addFive = addGenerator(5);

alert(addFive(10)); // 15
alert(plusOne(10)); // 11
于 2009-10-12T06:10:20.207 に答える
10

あまり詳しく説明しなくても、これは基本的にインスタンス変数のコピーを作成し、インスタンス変数をすぐに実行する関数にラップして、要素がクリックされたときに実行される関数に戻します。

次のように考えてください。

function() { alert(i); }  // Will expose the latest value of i
(function(I) { return function() { alert(I); }; })(i); // Will pass the current
                                                       // value of i and return
                                                       // a function that exposes
                                                       // i at that time

したがって、ループの各反復中に、変数の現在の値を持つ関数を返す関数を実際に実行しています。

ループに 4 つのアンカーがあると想像すると、次のように視覚化できる 4 つの個別の関数が作成されます。

function() { alert(0); };
function() { alert(1); };
function() { alert(2); };
function() { alert(3); };

この道をたどり、何が起こっているのか正確に理解していない場合、予期しない動作から大きな問題が発生する可能性があるため、javascript を使用してスコープとクロージャを調べることを検討します。

于 2009-10-12T06:06:23.113 に答える
2

onclick イベントがトリガーされると、無名関数が呼び出さiれ、ループで使用されたのと同じ変数を参照し、最後の値i4 を保持します。

問題の解決策は、関数を返す関数を使用することです。

a.onclick = (function(k) {return function() { alert(k); }; })(i);
于 2009-10-12T06:09:02.177 に答える