悪名高い JavaScript ループの問題は、ループを使用して動的に生成された要素にイベント ハンドラーをアタッチしようとすると発生します。次のスニペットでは:
function addLinks() { for (var i = 0, link; i < 5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function () { alert(i); // WRONG: i will always be 5 }; document.body.appendChild(link); } }
生成されたリンクのいずれかがクリックされると、アラートには常に「リンク 5」が表示されます。これは、var で定義された JavaScript の変数がブロック スコープではなく関数スコープであるためです。ループが終了すると、i は値 5 を保持し、すべての内部関数がそれを参照し、均一な出力が得られます。
修正された解決策は、クロージャ内で i の値をキャプチャすることにあります。次のスニペットを考えてみましょう:
function addLinks() { for (var i = 0, link; i < 5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function (num) { // Closure around i return function () { alert(num); // num retains its original value }; }(i); // Execute the outer function immediately to capture i document.body.appendChild(link); } }
この場合、num は各反復の i の現在の値にバインドされます。内部関数が実行されると、num はループ実行時の i の値に一貫して設定されます。
さらに、データの保存に DOM ノードを利用する効率的な代替手段が存在します。
function linkListener() { alert(this.i); } function addLinks() { for (var i = 0; i < 5; ++i) { var link = document.createElement('a'); link.appendChild(document.createTextNode('Link ' + i)); link.i = i; link.onclick = linkListener; document.body.appendChild(link); } }
DOM 要素自体に情報を付加することで、追加の関数オブジェクトの必要性が回避され、効率が向上します。
以上がイベント ハンドラーをアタッチするときに、JavaScript ループが常にカウンター変数の最終値を出力するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。