Что не так с моей областью javascript?
Следующие предупреждения 2
каждый раз.
function timer() {
for (var i = 0; i < 3; ++i) {
var j = i;
setTimeout(function () {
alert(j);
}, 1000);
}
}
timer();
Не следует ли var j = i;
установить j
в отдельную область setTimeout?
Если я это сделаю:
function timer() {
for (var i = 0; i < 3; ++i) {
(function (j) {
setTimeout(function () {
alert(j);
}, 1000);
})(i);
}
}
timer();
Он оповещает 0
, 1
, 2
как он должен.
Есть ли что-то, что мне не хватает?
Ответы
Ответ 1
Javascript имеет область действия. Это означает, что
for(...) {
var j = i;
}
эквивалентно
var j;
for(...) {
j = i;
}
Фактически, именно так компиляторы Javascript будут действительно обрабатывать этот код. И, конечно, это приводит к тому, что ваш маленький "трюк" терпит неудачу, потому что j
будет увеличиваться до того, как функция в setTimeout
будет вызвана, т.е. j
теперь на самом деле не делает ничего, кроме i
, это просто псевдоним с той же областью.
Если Javascript должен обладать блочной областью, трюк будет работать, потому что j
будет новой переменной на каждой итерации.
Что вам нужно сделать, так это создать новую область:
for(var i = ...) {
(function (j) {
// you can safely use j here now
setTimeout(...);
})(i);
}
Ответ 2
Альтернативой IIFE является функция factory:
function timer() {
for (var i = 0; i < 3; ++i) {
setTimeout(createTimerCallback(i), 1000);
}
}
function createTimerCallback(i) {
return function() {
alert(i);
};
}
timer();
Говоря это, это один из наиболее часто задаваемых вопросов в теге javascript. См:
Ответ 3
Альтернативой является использование ключевого слова (обычно злоупотребляемого) with
:
function timer() {
for (var i = 0; i < 3; ++i) {
with({j: i}) {
setTimeout(function () {
alert(j);
}, 1000);
}
}
}
timer();
Он создает новую область действия, как функции, но без неудобного синтаксиса. Я впервые увидел его здесь: Есть ли законные применения для JavaScript с инструкцией?