Пожалуйста, объясните замыкания или привязку счетчика цикла к области действия функции. - PullRequest
7 голосов
/ 24 января 2011

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

for(var i=0; i < someArray.length; i++){
   someArray[i].onclick = (function(i){/* Some code using i */})(i);
}

Может кто-нибудь объяснить, пожалуйста, логику этого и этот странный синтаксис, я никогда не видел этого:

(function(i))(i);

Большое спасибо за вашвремя и терпение.

Ответы [ 2 ]

7 голосов
/ 24 января 2011

Синтаксис (function(i))(i) создает анонимную функцию, а затем немедленно выполняет ее.

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

Так, например:

for(int i = 0; i < 10; i++)
    buttons[i].click = function() { doFoo(i); };

Часто ловит людей, потому что независимо от того, на какую кнопку вы нажимаете, doFoo(10) называется.

Принимая во внимание:

for(int i = 0; i < 10; i++)
    buttons[i].click = (function(i){ return function() { doFoo(i); };)(i);

Создает новый экземпляр внутренней функции (со своим собственным значением i) для каждой итерации и работает как ожидалось.

5 голосов
/ 24 января 2011

Это сделано потому, что JavaScript имеет только область действия , а не область блока.Следовательно, каждая переменная, которую вы объявляете в цикле, находится в области действия функции, и каждое создаваемое вами закрытие имеет доступ к той же самой переменной.

Таким образом, единственный способ создать новую область - это вызвать функцию, и эточто делает

(function(i){/* Some code using i */}(i))

.

Обратите внимание, что в вашем примере пропущена важная часть: немедленная функция должна вернуть другую функцию, которая будет обработчиком click:

someArray[i].onclick = (function(i){
    return function() {
       /* Some code using i */
    }
}(i));

Непосредственная функция ничего особенного.Это как-то встроенное определение функции и вызов функции.Вы можете заменить его обычным вызовом функции:

function getClickHandler(i) {
    return function() {
         /* Some code using i */
    }
}

for(var i=0; i < someArray.length; i++){
   someArray[i].onclick = getClickHandler(i);
}
...