web-dev-qa-db-ja.com

JavaScriptのクリックハンドラーがforループ内で期待どおりに機能しない

私はJSを学ぼうとしていますが、問題があります。

私は多くのことを試し、グーグルで検索しましたが、すべて無駄でした。次のコードは期待どおりに機能しません。クリックでiの値を取得する必要がありますが、常に6が返されます。髪を引っ張っています。

for (var i = 1; i < 6; i++) {

    console.log(i);

    $("#div" + i).click(
        function() {
            alert(i);
        }
    );
}

jsfiddle

224
JS-coder

ワーキングデモ

これは、従来のJavaScriptクロージャーの問題です。 iオブジェクトへの参照は、iの実際の値ではなく、クリックハンドラークロージャーに格納されています。

単一のクリックハンドラは同じオブジェクトを参照します。これは、6を保持するカウンタオブジェクトが1つしかないため、クリックごとに6を取得するためです。

回避策は、これを匿名関数でラップし、引数としてiを渡すことです。プリミティブは、関数呼び出しの値によってコピーされます。

for(var i=1; i<6; i++) {
     (function (i) {
        $("#div" + i).click(
            function () { alert(i); }
        );
     })(i);
}

[〜#〜] update [〜#〜]

更新されたデモ

または、varを宣言する代わりにiの代わりに 'let' を使用できます。 letは毎回新しいバインディングを提供します。 ECMAScript 6でのみ使用できますstrict mode

'use strict';

for(let i=1; i<6; i++) {

        $("#div" + i).click(
            function () { alert(i); }
        );
 }
132
Gurpreet Singh

問題は、ループを反復すると、iが増加することです。 alert(i)と言うと、javascriptにiの値が何であるかを伝えるように求めています。リンクをクリックします。その時点では6です。

代わりにボックスの内容を取得する場合は、次のようなことができます。

for (var i = 1; i < 6; i++) {

    console.log(i);

    $("#div" + i).click(function(e) {
        alert($(this).text());
    });
}

作業例: http://jsfiddle.net/rmXcF/2/

34
Maloric
$("#div" + i).click(
    function() {
        alert(i);
    }
);

iの値をクロージャーとして使用しているためです。 iは、foorループのすべての段階で増加するクロージャーを通じて記憶されます。

$("#div" + i).click(function(event) {
    alert($(event.target).attr("id").replace(/div/g, ""));
});
15
flavian