Затваряне на 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, тъй като лентата все още може да препраща към 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);
   }

За първата връзка num ще бъде 0, защото i беше едно, когато беше предадено на външната функция. i след това се повтаря за всеки ход на цикъла и ще бъде различна стойност за всяка връзка.

Моделът тук е много често срещан модел за запазване на текущата стойност на итерация на цикъл в обратни извиквания/обвързвания на събития.

person Ben McCormick    schedule 03.04.2013
comment
така че няма ли манипулаторът на събития да препраща към arg num при първото щракване? - 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