Это может помочь вам лучше понять, что происходит:
function timerCheck() {
for(var i=0; i<5; i++) {
console.log("Hi" + i);
setTimeout(function() {
console.log("Hello" + i);
}, 3000);
console.log("Bye" + i);
}
}
Вы увидите
Hi0
Bye0
Hi1
Bye1
Hi2
Bye2
Hi3
Bye3
Hi4
Bye4
Сразу же выводится на консоль, потому что все пять итераций цикла завершаются очень быстро, и через пять секунд вы увидите:
Hello5
Hello5
Hello5
Hello5
Hello5
потому что все тайм-ауты (которые были установлены приблизительно в одно и то же время) происходят одновременно, и поскольку цикл уже завершен: i == 5
.
Это вызвано областью действия i
. Переменная i
имеет область видимости повсюду после того, как она объявлена в timerCheck();
Внутри вашей анонимной функции в наборе setTimeout нет локального i, нет var i
, и i
не передается в качестве аргумента функция.
Вы можете легко исправить это с помощью замыкания, которое возвратит функцию с локальной копией i:
function timerCheck() {
for(var i=0; i<5; i++) {
setTimeout((function(loc_i) {
return function() {
console.log("Hello" + loc_i);
};
})(i), 3000);
}
}
Который выдаст:
Hello0
Hello1
Hello2
Hello3
Hello4
Чтобы понять это:
(function(loc_i) {
return function() {
console.log("Hello" + loc_i);
};
})(i)
Вы должны знать, что функция может быть немедленно выполнена в Javascript. IE. (function(x){ console.log(x); })('Hi');
выводит Hi
на консоль. Поэтому приведенная выше внешняя функция просто принимает аргумент (текущее значение i
) и сохраняет его в локальной переменной этой функции с именем loc_i
. Эта функция немедленно возвращает новую функцию, которая печатает "Hello" + loc_i
на консоли. Это функция, которая передается в тайм-аут.
Надеюсь, все это имело смысл, дайте мне знать, если вам все еще что-то неясно.