JavaScript の悪名高いループ問題が再考
JavaScript の悪名高いループ問題は、開発者を困惑させ続けています。次のコード スニペットを考えてみましょう:
function addLinks () { for (var i=0, link; i<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function () { alert(i); }; document.body.appendChild(link); } }
このコードは、現在のリンク ID を表示する onClick イベントを持つ 5 つのリンクを作成することを目的としています。ただし、これらのリンクをクリックすると、すべて「リンク 5」が表示されます。
この問題の根本原因は、JavaScript の関数レベルのスコープにあります。ループが完了すると、変数 i は値 5 を保持します。これは、Javascript 関数がその字句環境に対して閉じられており、周囲のスコープで定義された変数にアクセスできるためです。
この問題の回避策各反復で i の現在値をキャプチャするクロージャを導入することです:
function addLinks () { for (var i=0, link; i<5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function (num) { return function () { alert(num); }; }(i); document.body.appendChild(link); } }
このコードでは、リンクごとに新しい関数オブジェクトが作成されます。これには独自のスコープと、i の現在の値が割り当てられるローカル変数 num があります。内部関数が実行されると、クロージャの num 変数が参照され、ループ内に割り当てられた正しい値が保持されます。
このアプローチは効果的ですが、新しい関数が作成されるため、パフォーマンスが低下します。すべてのイベントリスナーに対して。より効率的な代替方法は、データ ストレージに 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); } }
i 値を DOM ノードに直接保存することで、クロージャの必要性がなくなり、コードの効率が向上します。
以上がJavascript ループがイベント ハンドラーで予期しない動作を引き起こすのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。