Область действия с функцией самовоспроизведения в Javascript - PullRequest
4 голосов
/ 16 ноября 2009

Приведенный ниже код перебирает 6 кнопок ввода и присоединяет событие onclick к каждой кнопке, которая сообщает номер индекса соответствующей итерации:

for (var i = 1; i < 6; ++i) {
    var but = document.getElementById('b_' + i);
    (function (el) {
        var num = i;
        but.onclick = function () {
            alert(num);
        };
    })(but);
}

Как вы можете видеть, в каждой итерации есть функция, вызывающая себя, которая создает область для хранения индекса итерации в этой области.

Я всегда использовал этот тип шаблона для добавления события, которое зависит от переменной, которая изменяется во время итераций.


Может кто-нибудь объяснить мне, почему вышеописанное работает, и как переменная num фиксируется в области видимости?

Кроме того, используемая выше функция самовоспроизведения называется closure?

Ответы [ 5 ]

8 голосов
/ 16 ноября 2009

Да, это закрытие.

Каждый раз, когда функция выполняется , создается новый объект для хранения (в качестве его свойств) переменных, объявленных с помощью var, и каждой функции, объявленной внутри нее. Этот объект называется контекстом выполнения (или иногда объектом области действия).

Каждый раз, когда функция объявляется (или определяется в выражении), новая функция присоединяет к ней объект контекста выполнения, который является текущим. Это создает так называемую цепочку областей действия.

Когда для выполнения кода требуется преобразовать идентификатор в значение, он сначала ищет его в свойствах текущего контекста выполнения. Если идентификатор не найден, он использует объект контекста освобождения, присоединенный к выполняемой функции. Он продолжает подниматься по цепочке, пока не достигнет глобального уровня.

В вашем примере каждый раз, когда выполняется «самовозглашающаяся функция», создается новый объект контекста выполнения, содержащий свойства el и num. Поскольку функция, назначенная onclick, создается внутри этого контекста выполнения, вы будете каждый раз получать новый экземпляр этой функции. Каждый из этих экземпляров будет иметь соответствующий объект контекста выполнения. Следовательно, первый будет иметь контекст выполнения, когда num был назначен 1, второй будет иметь контекст выполнения, где num был назначен 2 и т. Д.

Когда каждая из функций onclick запускается, код сначала ищет идентификатор num в текущем контексте выполнения. Однако эта внутренняя функция не изменяется, поэтому она не найдена. Таким образом, Javascript смотрит на контекст выполнения, присоединенный к функции, когда она была создана. Здесь он найдет num, num будет содержать значение, присвоенное ему во время этой итерации, как описано выше.

1 голос
/ 16 ноября 2009

Привет, ребята. Да, это закрытие. Если вы хотите знать, что именно происходит при создании функции, изучите следующую статью. http://www.jibbering.com/faq/faq_notes/closures.html

0 голосов
/ 18 декабря 2009
for (var i = 1; i < 6; ++i) {
    var but = document.getElementById('b_' + i);
    (function (el) {
        var num = i;
        but.onclick = function () {
            alert(num);
        };
    })(but);
}

Теперь давайте начнем выполнение цикла
вначале i = 1, но = купол с id = 'b1'
теперь идет вызов функции,
хорошо, он вызывает внутреннюю функцию (с параметром el) со значением параметра but ('b1') и начинает выполнять его, что на самом деле означает вызов, выполняйте его сейчас.
Теперь внутри него ,
новый экземпляр num назначен 1
but.onclick назначена функция, поэтому хранящаяся в памяти функция также видит, что она получает доступ к num, поэтому теперь num является закрытой переменной, что означает, что ее время жизни увеличивается, чтобы при вызове вызывать ее функцию.

Следующая итерация
теперь значение i = 2, но = купольная переменная с id = 'b2' теперь идет вызов функции,
он вызывает внутреннюю функцию (с параметром el) со значением параметра but (value = 'b2').
Теперь внутри него ,
новый экземпляр num назначен 2
but.onclick назначена функция, поэтому хранящаяся в памяти функция также видит, что она обращается к num, поэтому num теперь является закрытой переменной, что означает, что ее время жизни увеличивается, чтобы при вызове вызываться функцией onclick.
Подобно всем остальным, пока цикл не завершится.

0 голосов
/ 16 ноября 2009

Каждый раз при прохождении цикла оценка function (el) {...} создает новую анонимную функцию, которая вызывается немедленно. Внутри анонимной функции создается переменная с именем num (поскольку JS не выполняет статические переменные, она каждый раз новая). num присваивается значение i при вызове функции (что происходит немедленно). Это дает нам 6 анонимных функций и 6 num с, каждая из которых содержит значения от 1 до 6.

При каждом вызове анонимной функции создается внутренняя анонимная функция, которая сохраняется как обработчик щелчков. Внутренняя функция ссылается на num. В результате создается замыкание, которое гарантирует, что при выходе из внешней функции num не будет уничтожено. Если внутренняя функция когда-либо будет отброшена, вскоре последует num.

0 голосов
/ 16 ноября 2009

Не означает ли это, что var i, определенный за пределами closure, является глобальной переменной, предоставляя, таким образом, доступ к ней самовозбуждающейся функции?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...