2012-01-16 16 views
1

イベントを、divsの一連のイベントにforループを使用して追加しようとしました。 divsが動的に作成されてロードされます。すべてのdivは、独自のコールバック関数を呼び出すことになっています。しかし、すべてのdivが最終イベントリスナにアタッチされ、最終イベントリスナのコールバック関数を呼び出すようです。以下は新しいノードにイベントを追加します

私の基本的なコードです:クリックで

for(index=0; index<divs.length; index++) { 
    divs[index].addEventListener("click", function(){console.log(divs[index].getAttribute("id"));}, true); //capture click event 
} 

最終のdivのIDのみがすべてのdiv要素で表示されます。

+0

JavaScriptのクロージャについて読んで、コードを編集してください。これは可変スコープの問題です。 – DhruvPathak

答えて

8

Phil's answerは、あなたが投稿したコード(+1)に良い解決策を提供しますが、元のコードで何が問題だったかを説明しません。

問題は、イベントハンドラの閉鎖は、彼らが作成しているときのようindex変数ではなく、それのコピーから不朽の参照を得るということです。したがって、彼らはすべてindexが(divs.length)を持つ最終値を見る。タイムアウトが発生した場合、例えば、このコード

for (index = 0; index < 4; ++index) { 
    setTimeout(function() { 
     console.log(index); 
    }, 100); 
} 

はない... "0"、 "1"、 "2"、 "3"、 "4"、4回を記録します。

ハンドラが特定の値を閉じるようにする一般的なケースでは、イベントハンドラ関数を生成するファクトリ関数を使用して、イベントハンドラがファクトリに渡す引数を閉じる代わりに、ループ変数の機能は:

for(index=0; index<divs.length; index++) { 
    divs[index].addEventListener("click", createHandler(divs[index], true); //capture click event 
} 

function createHandler(div) { 
    return function(){ 
     console.log(div.getAttribute("id")); 
    }; 
} 

あり、イベント・ハンドラは変更されませんdiv、上で閉じます。

クロージャは、JavaScriptの最も強力な機能の1つです。彼らがどのように動作するかを理解すれば(そして、実際には思うよりもずっと簡単です)、それらを使って本当に効果的です。その他:Closures are not complicated

+0

+1大きな問題の説明。あなたの 'createHandler'メソッドは、IEの(<9)' attachEvent'でも動作しますが、私の場合はサポートされません( 'this'サポートが壊れています) – Phil

+0

@ T.J。クローダーの閉鎖は面白い、高すぎる –

3

これは、ループが完了した後に最後の要素に設定されたイベントハンドラでdivs[index]を使用しているためです。

代わりにthisを使用してください。また、あなたは、例えば

function logId(e) { 
    console.log(this.getAttribute("id")); 
} 

、代わりに同じ閉鎖の束を作成するための1つのイベントハンドラを使用することができます...そして、あなたのループで...

divs[index].addEventListener("click", logId, false); 

https://developer.mozilla.org/en/DOM/element.addEventListener#Memory_issues

+0

+1「this」を使用することをお勧めします。 –

+0

@Phil、ありがとう、これは助けます –

2

にあなたを参照してください。 @philによって指摘されたようにthisキーワードを使用できます。

しかし、あなたの問題は何であったかを説明するには、この閉鎖を検討してください:

for(index=0; index<divs.length; index++) { 
    (function(index){ 
     divs[index].addEventListener("click", function(){ 
      console.log(divs[index].getAttribute("id")); 
     }, true); 
    })(index); 
} 

、すべての関数は、のにindex変数の独自のコピーを取得します。あなたのコードでは、すべて同じ変数を共有します。したがって、最終的にindexは、divが実際にクリックされているかどうかにかかわらず、divs.length -1に等しくなります。

+0

あなたのイラストも同様ですが、私はまだあなたの助けを借りて(機能(arg){ステートメント})(arg)は、ありがとうございます –

関連する問題