Подтвердить что ты не робот

Что не так с моей областью 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 как он должен.

Есть ли что-то, что мне не хватает?

4b9b3361

Ответ 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 с инструкцией?