Задать вопрос
@6ondawave9

Почему переменная теряет видимость?

Если через консоль Chrome запустить код ниже, то все работает корректно
let testValue = 123;

function testFn() {
    let condition = 0;
    let timer = setTimeout(() => {
        console.log(testValue);
    });
}

testFn(); //123
Сколько угодно раз можно код запускать заново и все работает корректно.

Но при запуске такого же кода, но с добавлением условия
let testValue = 123;

function testFn() {
    let condition = 0;
    let timer = setTimeout(() => {
        if (condition === 0) {
            console.log(testValue);
        }
    });
}

testFn(); //123
при первом запуске все окей, но при повторных попытках получаю ошибку
Uncaught ReferenceError: Cannot access 'testValue' before initialization

Причем если условие заменить на true
ilet testValue = 123;

function testFn() {
    let condition = 1;
    let timer = setTimeout(() => {
        if (true) {
            console.log(testValue);
        }
    });
}

testFn(); //123
то все снова работает корректно

Также если убрать таймаут и поставить самовызывающуюся функцию
let testValue = 123;

function testFn() {
    let condition = 1;
    let timer = (() => {
        if (condition === 1) {
            console.log(testValue);
        }
    })();
}

testFn(); //123
то тоже все нормально

Если весь код обернуть в самовызывающуюся функцию тоже все нормально
(()=>{
    let testValue = 123;

    function testFn() {
        let condition = 1;
        let timer = setTimeout(() => {
            if (condition === 1) {
                console.log(testValue);
            }
        });
    }
    
    testFn();
})();

Если не декларировать заново переменную testValue
let testValue = 123;
то тоже все окей
Вопрос знатокам почему так? Чувствую, что замешаны замыкания и переопределение контекста, но поведение похоже больше на какой-то баг
  • Вопрос задан
  • 510 просмотров
Подписаться 2 Простой 4 комментария
Решения вопроса 1
sergiks
@sergiks Куратор тега JavaScript
♬♬
Похоже на баг/фичу консоли Google Chrome.
В консоли FireFox повторные запуски корректно ругаются на переобъявление let testValue

Так действительно делать нельзя, но разрабы Chrome с версии 80 решили «помочь» разработчикам, использующим консоль, и ленящимся заключать весь код в фигурные скобки, чтобы изолировать область видимости. С FireFox такая привычка у меня лично уже выработалась, все эксперименты в консоли – внутри { }

И вот в консоли Хрома теперь можно переназначать и переенные let, и даже const. И классы. Печаль.

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

TL&DR; предлагаю писать корректный JS в строгих песочницах, где два let подряд не пройдут.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы