4

可能重复:
循环内的 Javascript 闭包 - 简单的实际示例

最近我一直在研究 JavaScript 的一些更复杂的方面,其中之一就是设计模式和委托。

我创建了一个包含 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 回答