Области применения JavaScript с закрытием: помогите мне понять - PullRequest
5 голосов
/ 09 сентября 2010

Запуск следующего кода:

for (var i=0; i<3; i++) { 
   setTimeout( function() { console.log(i); } , 500 ); 
}

Выводит «3» три раза. Он выводит окончательное значение i вместо значения i при создании внутренней функции.

Если я хочу, чтобы выходные данные были 1, 2 и 3, как бы я написал этот код? Как я могу заставить его использовать значение i в то время, когда функция определена в отличие от ее окончательного значения?

Ответы [ 4 ]

6 голосов
/ 09 сентября 2010
for (var i=0; i<3; i++) {
   setTimeout( function(val) { return function() { console.log(val); } }(i), 500 );
}

Итак, во время setTimeout (в то время, когда мы определяем функцию для setTimeout), мы вызываем анонимную функцию, принимающую val в качестве параметра.Это создает замыкание для каждого вызова функции, сохраняя значение val в пределах только что вызванной функции.Я использовал самовозглашающуюся функцию , которая создает немедленное замыкание .

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

4 голосов
/ 09 сентября 2010
function f(i){
  return function(){console.log(i);};
}

for (var i=0; i<3; i++) { 
   setTimeout( 
     f(i)
   , 500 ); 
}
2 голосов
/ 09 сентября 2010

Современная альтернатива явному замыканию (которое может показаться немного сложным для чтения, когда у вас есть двойная функция) - Function#bind.После того, как вы взломали поддержку для браузеров, которые еще не используют ECMAScript Fifth Edition, вы можете сказать:

for (var i=0; i<3; i++) {
    setTimeout(function(i) { console.log(i); }.bind(window, i), 500);
}

window - это значение, которое будет thisбыть внутри функции (вам не нужно this здесь, поэтому мы просто используем глобальный объект по умолчанию).В случае, когда вы просто вызываете другую функцию / метод, как здесь с console.log, вы можете использовать это для полного удаления выражения функции:

for (var i=0; i<3; i++) {
    setTimeout(console.log.bind(console, i), 500);
}
1 голос
/ 09 сентября 2010

альтернатива:

for (var i=0; i<3; i++) {
   (function(val){
       setTimeout(function() {
           console.log(val);
       },500)
   }(i));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...