2011-11-30 12 views
3

私はこのコードが動作しないことを知っていますし、私も理由を知っています。しかし 、私はそれを修正する方法がわからない:ループ変数に匿名関数を定義していますか?

JavaScriptを:

var $ = function(id) { return document.getElementById(id); }; 
document.addEventListener('DOMContentLoaded', function() 
{ 
    for(var i = 1; i <= 3; i++) 
    { 
     $('a' + i).addEventListener('click', function() 
     { 
      console.log(i); 
     }); 
    } 
}); 

HTML:

<a href="#" id="a1">1</a> 
<a href="#" id="a2">2</a> 
<a href="#" id="a3">3</a> 

は、私は、それはあなたがクリックしたリンクの数を印刷したくないだけ」 4 "となる。 ノードの属性(IDまたはコンテンツ)を使用するのではなく、ループを修正することをお勧めします。

+0

[Coffeescript](http://coffeescript.org/)は、この種の状況のた​​めに非常に便利な 'do'キーワードを持っています。 –

答えて

5

ラップ独自の匿名関数でループブロック:

document.addEventListener('DOMContentLoaded', function() 
{ 
     for(var i = 1; i <= 3; i++) 
     { 
      (function(i) { 
       $('a' + i).addEventListener('click', function() { 
        console.log(i); 
       }) 
      })(i); 
     } 
} 

これは、各呼び出し/繰り返しで内部関数に対してローカルですiの新しいインスタンスを作成します。このローカルコピーがなければ、(各繰り返しで)addEventListenerに渡された各関数は、同じ変数のへの参照をクローズします。その値は、コールバックが実行される時刻までに4に等しくなります。

3

問題は、内部関数がi以上のクロージャを作成していることです。これは、基本的には、ハンドラを設定するときに関数がiの値を記憶するのではなく、変数i自身を記憶していることを意味します。ライブ参照をiに保存しています。

あなたはそれがiコピーが行われることになりますから、関数にiを渡すことによってブレーク閉鎖する必要があります。

これを行う一般的な方法は、即座に実行される無名関数によるものです。

 for(var i = 1; i <= 3; i++) 
     { 
      $('a' + i).addEventListener('click', (function(localI) 
      { 
       return function() { console.log(localI); }; 
      })(i); 
     } 

すでにjQueryのを使用しているので、私はjQueryのは、このようなコードを簡素化するために使用することができますdata機能を提供することを言及します:ここで

 for(var i = 1; i <= 3; i++) 
     { 
      $('a' + i).data("i", i).click(function() 
      { 
       console.log($(this).data("i")); 
      }); 
     } 

を、代わりので閉鎖を破りますiを無名関数に渡す場合は、iをjQueryのdata関数に渡すことで破棄します。

+0

+1はクロージャの問題を説明するためのものです。 – link664

+0

私はjQueryを基本的な$ = document.getElementById;だけで使用していませんでした。 – Tyilo

+0

'$( 'a' + i).clickの代わりに' $( 'a' + i).addEventListener'をやっていたのは不思議でした。 ' - ああ、いくつかの余計なjQuery情報:) –

0

クロージャは、コピーではなく変数への参照を取得します。そのため、すべてが 'i'の最後の値になっています。

コピーをキャプチャする場合は、別の機能でコピーする必要があります。

関連する問題