4

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

最近、私は JavaScript のより複雑な側面のいくつかをいじっています。その 1 つはデザイン パターンと委譲です。

2 つのキーを含むオブジェクトを作成し、それを解析してイベントを本体に添付します。

私の問題は、 for ループの繰り返しに最後の関数が添付されているように見えることです。これは参照/スコープによるコピー (Shmiddty に感謝) の問題であると確信していますが、間違っている場合は修正してください。

あまり変更せずに2つのイベントを適切に添付するために私の問題を修正する方法はありますか? (これは複雑なアプリであるため、目前の問題まで単純化しました)。

jsfiddle の.div1で、アラート メッセージが次のようになっていることを確認してください。.div2

var foo = {
    init: function() {

        var i = 0,
            keys = []
            self = this;

        for (var key in this) {
            keys.push(key);
        }

        for (i; i < keys.length; i++) {
            if (keys[i].match(/^on/i)) {
                var delegateFunc = keys[i].split(' | '),
                    event = delegateFunc[2],
                    selector = delegateFunc[1],
                    keyName = keys[i];

                console.log('###');
                console.log( 'selector: ' + selector );
                console.log( 'event: ' + event );
                console.log( 'function: ' + self[keyName] );

                $('body').on(event, selector, function(ev) {
                    self[keyName](ev, ev.target);
                });
            }
        }

    },

    'on | .div1 | click': function(ev, el) {
        alert('you clicked 1');
    },

    'on | .div2 | click': function(ev, el) {
        alert('you clicked 2');
    }
}

$(function() { foo.init(); });​

さらに情報が必要ですか?コメントを残してください。乾杯

4

3 に答える 3

2
            $('body').on(event, selector, function(ev) {
                self[keyName](ev, ev.target);
            });

これを次のコードに置き換えます。

            (function(keyName) {
                $('body').on(event, selector, function(ev) {
                    self[keyName](ev, ev.target);
                });
            })(keyName);

これは、JavaScript にブロック スコープがないためです。したがって、あなたvar keyNameは各ループで同じ変数であり、コールバック関数のクロージャーは、その時点での値ではなく、変数をバインドします。したがって、ループが終了するとすぐに、変数はすべてのコールバック関数の最後の値になります。

引数としてすぐに実行される関数を追加することで、新しい変数 (関数の引数)keyNameを作成し、問題を回避します。

于 2013-01-04T00:21:23.583 に答える
1

古典的な閉鎖問題..

forループをすぐに呼び出される関数式に入れます

for (i; i < keys.length; i++) {
            (function(lockedIndex) {
                if (keys[lockedIndex].match(/^on/i)) {
                    var delegateFunc = keys[lockedIndex].split(' | '),
                        event = delegateFunc[2],
                        selector = delegateFunc[1],
                        keyName = keys[lockedIndex];

                    console.log('###');
                    console.log('selector: ' + selector);
                    console.log('event: ' + event);
                    console.log('function: ' + self[keyName]);

                    $('body').on(event, selector, function(ev) {
                        self[keyName](ev, ev.target);
                    });
                }
            })(i)
        }

フィドルをチェック

于 2013-01-04T00:21:14.853 に答える
0

keyNameイベントハンドラーがトリガーされるまでに古い場合、新しいスコープでラップする必要があります。

(function(key) {
    $('body').on(event, selector, function(ev) {
        self[key](ev, ev.target);
    });
})(keyName);
于 2013-01-04T00:21:44.990 に答える