Почему мое использование «let» не предотвращает классическую проблему закрытия с setTimeout и последовательными переменными? - PullRequest
0 голосов
/ 18 декабря 2018

См. Этот код:

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

Это классическая ошибка, когда она печатает окончательное значение i несколько раз вместо печати требуемого последовательного вывода.

Я знаю, что можетисправить это, используя let вместо var:

for(let i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, 200);
}

Меня смущает то, почему не исправляет это:

for(var i = 0; i < 5; i++) {
    setTimeout(function() {
        let n = i;
        console.log(n);
    }, 200);
}

Теперь это должно быть исправлено по той же причине, что и предыдущий код, но ошибка сохраняется.Почему это так?

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018

Существует специальное поведение для объявлений let в заголовке цикла for.Переменная объявляется уникально для каждой итерации.Вот почему пример № 2 «работает».

В примере № 3 объявление var i происходит только один раз, и значение обновляется на каждой итерации.let также объявляется во время выполнения.Таким образом, каждый раз, когда выполняется функция обратного вызова в примере # 3, в первый раз после ВСЕХ итераций цикла for объявляется let n = i (во время выполнения) и i в это время - единственный i это было объявлено в цикле for.

Я рекомендую просто прочитать это очень быстро.https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch5.md#block-scoping-revisited

console.log(a);
var a = 10;

напечатает undefined, поскольку во время console.log a было объявлено, но не назначено.

console.log(a);
let (or const) a = 10;

выдаст TypeError, потому чтона момент console.log a еще не было объявлено.

0 голосов
/ 18 декабря 2018

Вы по-прежнему ссылаетесь на i в функции обратного вызова setTimeout, поэтому у вас все еще есть замыкание вокруг нее.Это на самом деле ничем не отличается от вашего первого примера «классической» проблемы закрытия с таймерами.

Причина, по которой пример let избегает этой проблемы, заключается в том, что, хотя на i ссылаются в обратном вызове таймера, этоне то же самое i, как в предыдущей итерации цикла.Каждая итерация получает свою собственную i.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...