1

重複の可能性:
ループ内の Javascript クロージャー - 簡単な実用例

4 つのオブジェクト ( that.pairs) の配列があり、各オブジェクトには.tjQuery オブジェクト/要素であるプロパティがあります。tクリックされるたびにイベントを設定しようとしています。

doToggle()問題は、それらのいずれかがクリックされると、関数に渡されるのは常に最後のペア (インデックス 3) になることです。

なぜこうなった?どうすれば修正できますか?

for (var i = 0; i < that.pairs.length; i++) {
    var p = that.pairs[i];
    p.t.click(function() {
        that.doToggle(p);
    });
}
4

4 に答える 4

4

これは、p変数がクロージャによって共有されているためです。p 変数は 1 つだけです。ハンドラーが呼び出されるまでに、 p は変更されています。

クロージャーを凍結するというテクニックを使用する必要があります

for (var i = 0; i < that.pairs.length; i++) {
    // The extra function call creates a separate closure for each
    // iteration of the loop
    (function(p){
        p.t.click(function() {
            that.doToggle(p);
        });
    })(that.pairs[i]); //passing the variable to freeze, creating a new closure
}

これを達成するためのより簡単な方法は次のとおりです。

function createHandler(that, p) {
    return function() {
       that.doToggle(p);
    }
}

for (var i = 0; i < that.pairs.length; i++) {
    var p = that.pairs[i];
    // Because we're calling a function that returns the handler
    // a new closure is created that keeps the current value of that and p
    p.t.click(createHandler(that, p));
}

閉鎖の最適化

コメントでクロージャーとは何かについて多くの議論があったので、クロージャーが最適化され、必要な変数だけが囲まれていることを示すこれらの 2 つのスクリーンショットを掲載することにしました。

この例http://jsfiddle.net/TnGxJ/2/のみがどのようaに囲まれ ているかを示しています評価なしの閉鎖

この例http://jsfiddle.net/TnGxJ/1/では、 があるためeval、すべての変数が囲まれています。 eval によるクロージャ

于 2012-11-29T00:03:58.413 に答える
3

$.eachループの代わりに使用forして、反復ごとに新しい変数スコープを取得します。

$.each(that.pairs, function(i, p) {
    p.t.click(function() {
        that.doToggle(p);
    });
});

このようにして、各clickハンドラーは、共有された外部変数スコープではなく、一意の変数スコープを閉じます。

于 2012-11-29T00:04:34.567 に答える
1
for (var i = 0; i < that.pairs.length; i++) {
    var p = that.pairs[i];
    (function(p){
        p.t.click(function() {
            that.doToggle(p);
        });
    }(p));
}

IIFE を使用したこのトリックは、現在発生している閉鎖の「問題」を解決します。

于 2012-11-29T00:03:47.450 に答える
1
for (var i = 0; i < that.pairs.length; i++) {
    (function(num){
       var p = that.pairs[num];
       p.t.click(function() {
          that.doToggle(p);
       });
    })(i)
}

古典的な閉鎖の問題

それらを無名関数で囲み、現在の反復をコンテキストに割り当てます。それは問題を解決するはずです..

于 2012-11-29T00:03:55.197 に答える