Привязка переменных JavaScript и цикл
Рассмотрим такой цикл:
for(var it = 0; it < 2; it++)
{
setTimeout(function() {
alert(it);
}, 1);
}
Вывод:
=> 2
=> 2
Мне бы хотелось: 0, 1. Я вижу два способа исправить это:
Решение № 1.
Это основано на том, что мы можем передавать данные в setTimeout.
for(var it = 0; it < 2; it++)
{
setTimeout(function(data) {
alert(data);
}, 1, it);
}
Решение № 2.
function foo(data)
{
setTimeout(function() {
alert(data);
}, 1);
}
for(var it = 0; it < 2; it++)
{
foo(it);
}
Есть ли другие альтернативы?
Ответы
Ответ 1
На самом деле не больше, чем два способа, которые вы предложили, но здесь другой
for(var it = 0; it < 2; it++)
{
(function() {
var m = it;
setTimeout(function() {
alert(m);
}, 1);
})();
}
По существу, вам нужно зафиксировать значение переменной в закрытии. Этот метод использует сразу вызываемую анонимную функцию для захвата значения внешней переменной it
в локальной переменной m
.
Здесь Рабочий демонстрационный пример. добавьте /edit в URL-адрес, чтобы увидеть код
Ответ 2
С ключевым словом let вы можете обойти это полностью:
for(let it = 0; it < 2; it++)
{
setTimeout(function() {
alert(it);
}, 1);
}
Ответ 3
Подобно описанному выше решению, но сам вызывающий внутри функции setTimeout
for(var it = 0; it < 2; it++)
{
setTimeout(function(cur) {
return function(){
alert(cur);
};
}(it), 1);
}
Ответ 4
Подобно другим решениям, но, по-моему, чище:
for (var it = 0; it < 2; it++) {
// Capture the value of "it" for closure use
(function(it) {
setTimeout(function() {
alert(it);
}, 1);
// End variable captured code
})(it)
}
Это сохраняет одно и то же имя переменной для захвата и делает это для всего цикла, отделяя это от логики настройки таймаута. Если вы хотите добавить больше логики внутри блока, вы можете это сделать тривиально.
Единственное, что мне не нравится в решении, это повторение "it" в конце.