2012-03-22 8 views
0

button要素の束を生成し、DOM機能を介してbodydivに追加するコードがあります。の機能(イベントハンドラ)をonclickイベントのそれぞれbuttonに動的に設定します。ルーピングとクロージャ

0から20までを繰り返すことによって実行されます。

問題は、私はイベントハンドラでループカウンタiを使用したいと思いますが、最終的な値ではなくループの反復で値が得られます。iが得られます。最初は、私は閉鎖によってこれを行うことができると思ったが、その後私はそれが当初考えていた方法を実行しなかったことに気づいた。 iは各反復を変更し続け、他のすべてのanon関数(クロージャを介して)は、範囲内のiがすべて同じ値を指しているという点で同じiを参照する必要があります。 onclickをトリガーすると、すべて同じ値を報告するためです。

だから、私はそれを修正するにはどうしたらいいですか?私はiを別の変数に設定しようとしましたが、そのような新しい変数はちょうどiというようにそれぞれの反復を更新しているので、同じ結果になります。私はここに簡単なものがないと思う。

<!DOCTYPE html> 
<html> 
<head> 
    <title>loop closure test</title> 

<script language="javascript" type="text/javascript"> 
window.onload = function() { 

    var div = document.getElementById("myDiv"); 

    for(var i = 0; i <= 20; i++) { 
     var b = document.createElement("button"); 
     b.setAttribute("type","button"); 
     b.appendChild(document.createTextNode("Button" + i.toString())); 
     b.onclick = function(event) { 
      var date = new Date(2012, 3, i); 
      alert(date.getMonth() + "/" + date.getDate() + "/" + date.getFullYear()); 
     }  
     div.appendChild(document.createElement("br")); 
     div.appendChild(b); 
    }  
} 
</script> 

</head> 

<body> 
<div id="myDiv"></div> 
</body> 

</html> 

私はそれについてもう少し考えてみました。基本的に私はiを別のクロージャの中に閉じ込める必要がありました。私はこのルートで行くことにしました:

<!DOCTYPE html> 
<html> 
<head> 
    <title>loop closure test</title> 

<script language="javascript" type="text/javascript"> 
window.onload = function() { 

    var div = document.getElementById("myDiv"); 

    for(var i = 0; i <= 20; i++) {   
     div.appendChild((function() { 
      var day = i; 
      var b = document.createElement("button"); 
      b.setAttribute("type","button"); 
      b.appendChild(document.createTextNode("Button" + i.toString())); 
      b.onclick = function(event) { 
       var date = new Date(2012, 3, day); 
       alert(date.getMonth() + "/" + date.getDate() + "/" + date.getFullYear()); 
      } 


      return b; 
     }())); 

     div.appendChild(document.createElement("br")); 

    } 

} 
</script> 

</head> 

<body> 
<div id="myDiv"></div> 
</body> 

</html> 
+1

[JavaScriptでのループのためにクリックハンドラを割り当て]の可能な重複(http://stackoverflow.com/questions/8881306/assign-click-in-for-in-loop-in-javascript) – Pointy

+0

はい、各ループのクロージャで動作します。 – Bergi

+0

重要なことは、JavaScriptのローカル変数が関数レベルでスコープされていることです。したがって、各ハンドラに独自の "i"を与えたい場合は、* another *関数でハンドラ関数をインスタンス化する必要があります。 StackOverflowには、この問題に関する質問がたくさんあります。 – Pointy

答えて

1

はこのようにクロージャを使用してみてください:

var div = document.getElementById("myDiv"); 

for(var i = 0; i <= 20; i++) { 
    var b = document.createElement("button"); 
    b.setAttribute("type","button"); 
    b.appendChild(document.createTextNode("Button" + i.toString())); 
    b.onclick = function(pos) { 
     return function(event) { 
       var date = new Date(2012, 3, pos); 
       alert(date.getMonth() + "/" + date.getDate() + "/" + date.getFullYear()); 
     } 
    }(i);  
    div.appendChild(document.createElement("br")); 
    div.appendChild(b); 
} ​