Нужно ли закрытие внутри обратного вызова события DOM? - PullRequest
0 голосов
/ 19 февраля 2012

Я пытаюсь создать функцию, подобную jQuery.live. Helper - это класс с методами _liveEvent и _addEventListener. Helper._addEventListener - это просто версия CrossBrowser W3C addEventListener.

Helper.prototype._liveEvent = function(type, evt, ofunc) {
    var elHand = document;
    type = type.toUpperCase();

    this._addEventListener(elHand, evt, function(me) {
        // Inside here I use the `type` variable.
        // I don't know why but it works.

        for (var el = me.srcElement; el.nodeName !== 'HTML';
            el = el.parentNode)
        {
            if (el.nodeName === type || el.parentNode === null) {
                break;
            }
        }
        if (el && el.nodeName === type) {
            ofunc.call(el, me);
        }

    });
};

Я запускаю функцию Helper._liveEvent 2 раза с разными типами. И это работает просто отлично. Я думал, что поскольку переменная type была установлена ​​внутри контекста _liveEvent, обратный вызов _addEventListener мог видеть только последнюю версию этой переменной. Но дело не в этом, похоже, работает нормально.

Мои вопросы:

  • Почему обратный вызов _addEventListener может видеть обе версии типа?
  • Означает ли это, что мой код пропускает память?

UPDATE

Этот другой пример заставил меня лучше понять это. Но я не уверена, что я все же это поняла.

function foo(i) {
    setTimeout(function() {
        console.log(i);
    }, 400);

}

// Prints 1, 2, 3
for (var i = 1; i < 4; i++) {
    foo(i);
}

function bar() {
    for (var i = 1; i < 4; i++) {
        setTimeout(function() {
            console.log(i);
        }, 400);
    }
}

// Prints 4, 4, 4
bar();
​

Ответы [ 2 ]

1 голос
/ 19 февраля 2012
  • Это потому, что для каждого экземпляра анонимной функции, переданной в _addEventListener(), создается отдельная область замыкания, каждый из которых имеет свои собственные значения elHand и type.
  • Это зависит от того, что вы подразумеваете под "утечкой". Каждое закрытие предотвращает объекты, которые оно содержит, от GC'ing. Замыкание выполняется GC, когда больше нет объектов (скажем, анонимных функций, подобных вашей), ссылающихся на него. В этом смысле, да, у вас есть утечка памяти, поскольку у вас нет возможности удалить добавленный прослушиватель (анонимная функция), что делает связанный объект области действия приемлемым для GC.
1 голос
/ 19 февраля 2012

По сути, вы уже создаете замыкание. Вот почему:

for( var i=0; i<10; i++) {
    elem.onclick = (function(id) {alert(id);})(i);
}

работает - вызов анонимной функции создает новое замыкание с id, для которого установлено текущее значение i. (Лично мне нравится называть аргумент тем же, что и переменная, которую я хочу использовать, поэтому я могу думать о ней как о «блокировке» значения переменной для этой функции).

Что касается утечек памяти, то два вызова не вызовут утечку. Если GC работает так, как я думаю, он удаляет все замыкания, на которые нет указателей. В частности, когда вы покидаете страницу, любая память, связанная с этой страницей, освобождается.

...