Закрытие Javascript и его область действия

for (var i=0, link; i<5; i++) {
    link = document.createElement("a");
    link.innerHTML = "Link " + i;
    link.onclick = function (num) {
        return function () {
            alert(num);
        };
    }(i);
    document.body.appendChild(link);
}

Поскольку вложенная функция является закрытием, она имеет ссылку на аргумент num, аргумент num в конце цикла равен 4. Теперь, когда нажимается первый элемент, почему он предупреждает 1? Он должен предупреждать 4. В чем причина для оповещения 1? Разве это не ссылка на аргумент num? Или в чем причина?

Но здесь дело обстоит иначе:

function foo(x) {
    var tmp = 3;
    return function (y) {
       alert(x + y + (++tmp));
    }
}
var bar = foo(2); // bar is now a closure.
bar(10);

Вышеупомянутая функция предупредит 16, потому что bar по-прежнему может ссылаться на arg x и tmp, даже если он больше не находится непосредственно внутри области видимости.

Это доказывает, что закрытие также имеет ссылку на значение аргументов, чем почему приведенный выше код не предупреждает 4 каждый раз?


person Maizere Pathak.Nepal    schedule 03.04.2013    source источник
comment
Он предупреждает 1 при нажатии на первый элемент, поскольку вы передаете аргумент i на текущей итерации внутренней функции onclick, которая имеет аргумент num.   -  person Anthony Forloney    schedule 03.04.2013
comment
На этот вопрос о SO есть несколько отличных ответов, которые помогут вам понять замыкания   -  person excentris    schedule 03.04.2013
comment
На самом деле должно быть предупреждение 0, так как это первое #, которое вы передаете   -  person Ben McCormick    schedule 03.04.2013


Ответы (2)


  for (var i=0, link; i<5; i++) {  //i starts at 0 and iterates up to 4
        link = document.createElement("a");
        link.innerHTML = "Link " + i;


         link.onclick = function (num) {
            //num is never changed within this function, and is equal
            //to the value of i when it was passed in

            return function () { alert(num);};

        }(i);  //i is passed here
        //that sets num to the current value of i for each link

        document.body.appendChild(link);
   }

Для первой ссылки номер будет равен 0, потому что i был единицей, когда он был передан внешней функции. Затем i повторяется для каждого оборота цикла и будет другим значением для каждой ссылки.

Шаблон здесь является очень распространенным шаблоном для сохранения текущего значения итерации цикла в привязках обратных вызовов/событий.

person Ben McCormick    schedule 03.04.2013
comment
так что обработчик событий не будет ссылаться на номер аргумента при первом щелчке? - person Maizere Pathak.Nepal; 03.04.2013
comment
да. и num сохраняется замыканием как значение i, когда свойство onclick было впервые установлено. - person Ben McCormick; 03.04.2013

То, что вы делаете, является классическим примером избежания того, что нажатие на первый элемент даст вам 4 вместо 1, что должно быть наиболее ожидаемым значением.

Если вы хотите, чтобы он предупреждал 1, просто сделайте это:

link.onclick = function() {alert(i);};

Но, честно говоря, какой в ​​этом смысл? Все 4 ссылки будут предупреждать 4...

person MaxArt    schedule 03.04.2013