2013-04-07 5 views
-2
function addLinks() { 
    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); 
}} 

Закрытие создается для каждой ссылки; каждое закрытие имеет ссылку на область, в которой она была создана. Поскольку аргумент num был обновлен в каждом цикле, на click по первой ссылке, он должен предупредить 4. Не так ли?Разница между локальными переменными и аргументами

+0

Аргумент num никогда не обновляется, это новая переменная для каждого вызова. – bfavaretto

ответ

2

Вовсе нет, каждый вызов функции получает новую копию переменной num поэтому первое звено должно насторожить 0.

Если вы действительно хотите иметь все обратные вызовы разделяют ту же переменную ... то просто они разделяют ту же переменную (обертка «Num» материал был точно, чтобы избежать этой проблемы, и пусть обратные вызовы независимы):

//now all the inner closures use the same "i" variable 
//since the variable gets mutated by the for loop 
//all links are going to print "5" after the loop ends. 
for (var i=0, link; i<5; i++) { 
    link = document.createElement("a"); 
    link.innerHTML = "Link " + i; 
    link.onclick = function() { 
     alert(i); 
    }; 
} 

Кстати, это происходит только потому, что, в отличие от других языков, JS не имеет область блока для индексов цикла. Цикл ведет себя, как если бы вы сделали

var i; 
while(i < 5){ 
    //... 
    i++ 
} 
+1

Следует упомянуть, что JS имеет функциональную область действия, а «i'« живет »в функции, а не в цикле (или на итерации). – Joseph

1

No.

А потому, что ты путаешь две вещи:

  1. аргументы функции являются локальными по отношению к функции (с большой «если», сохраненный для номера 2)
    Они предназначены для псевдонима объекта (включая массивы/функции) или значения для области действия под любым именем, которое вы выберете.
    Цель состоит в том, чтобы вы могли переименовать свой параметр во все, что хотите, для того, чтобы сделать внутренний код понятным, независимо от того, что вы передаете в качестве аргумента из внешнего кода.
    Это не имеет никакого отношения к сфере применения.

  2. переменные в JS передаются по ссылке, если они являются объектами, и по значению, если они являются скалярами.
    Всего смыслом прохождения i в новое закрытия является то, что значения из i в настоящее время передаются в качестве аргумента, а не ссылки к i, что и происходит, если вы Дона» t включают в себя закрытие.

Если вы должны были передать объект, и объект был то, что было i на нем (obj.i += 1), а затем снова, закрытие или нет, каждая функция будет указывать на ту же ценность i, потому что они d все используют одну и ту же ссылку на один и тот же объект.

объекты передаются по ссылки, скаляров передаются по значения.
Несмотря на то, что объекты с целыми и числовыми объектами технически являются, они преобразуются в скалярные значения, как только вы ничего не делаете объектно-ориентированными с ними.

var i = 3, 
    say_i = function() { console.log(i); }; 

против

var i = 3, 
    say_i = (function (val) { return function() { console.log(val); }(i)); 

Первый дает , присвоенный к i.
Когда запускается say_i, он смотрит на значение i в режиме реального времени и плюет на консоль.

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

Вы также могли бы достичь этого же результата, если вы сделали функцию один раз, вне цикла:

var add_log = function (el, val) { el.onclick = function() { console.log(val); }; }, 
    i = 0, 
    el; 

for (; i < ........) { 
    el = .... 
    add_log(el, i); 
} 

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

Смежные вопросы