Когда невозможно определить, был ли инициализирован let или const?

В своей статье о let и const Джейсон Орендорф заявляет следующее:

Краткие сведения о производительности: в большинстве случаев вы можете сказать, было ли выполнено объявление, просто взглянув на код, поэтому движку JavaScript фактически не нужно выполнять дополнительную проверку каждый раз при доступе к переменной, чтобы убедиться, что она была инициализирована. . Однако внутри замыкания это иногда неясно. В этих случаях движок JavaScript выполнит проверку во время выполнения. Это означает, что let может быть немного медленнее, чем var.

Я решил попытаться найти пример, где это верно, и был поставлен в тупик.

Например, давайте посмотрим на следующий сценарий пыток:

function doSomethingDumb(q) {
    function crash() { ++x; }
    q.fn = crash;
    crash();
    let x;
    return crash;
}

Несмотря на то, что замыкание возвращается в конце функции, гарантируется, что оператор return никогда не будет выполняться, даже если x назначен члену q (и, таким образом, может уйти в дикую природу) x никогда не будет инициализирован, поэтому crash всегда будет падать.

В каком случае нельзя было бы сказать, инициализирована ли переменная?


person JeremiahB    schedule 11.04.2017    source источник
comment
crash() даже не будет выполняться, он уже вылетает при попытке назначить x на q.fn.   -  person Bergi    schedule 11.04.2017
comment
Это должно было быть q.fn = крах. Спасибо, что поймали это.   -  person JeremiahB    schedule 11.04.2017
comment
Кстати, а можно ссылку на статью с этой цитатой?   -  person Bergi    schedule 11.04.2017
comment
Дело сделано.   -  person JeremiahB    schedule 11.04.2017


Ответы (2)


Просто поместите это в условие, которое выполняется лишь иногда:

function example() {
    if (Math.random() < 0.33) tryIt();
    const x = 5;
    if (Math.random() < 0.5) tryIt();
    function tryIt() {
        console.log(x);
    }
}

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

person Bergi    schedule 11.04.2017
comment
@BekimBacaj Вопрос был Вот пример, и совершенно ясно, инициализируется ли x при доступе или нет; в каком случае это не ясно?, и я показал пример, где это не так просто увидеть и что это не может быть определено в каждом случае. - person Bergi; 11.04.2017

Не существует такой вещи, как медленный или быстрый дескриптор, то есть именованное значение, будь то var, const или let. Нет такой вещи, как «невозможно определить», инициализированы ли они. Более того, let/s не инициализируются - они просто назначаются. А так как они действуют аналогично «необъявленным переменным», им будет присвоено их значение во время выполнения и точно в момент их объявления.

Поэтому, если произойдет стоп-ошибка, она появится всего на одну строку выше объявления let. Он останется полностью необъявленным. Вы узнаете это, просто взглянув на код.

person Bekim Bacaj    schedule 11.04.2017
comment
Возможно, вы захотите взглянуть на это, чтобы узнать, что означают объявление и инициализация для let/const. - person Bergi; 11.04.2017
comment
Хм, они совсем не похожи на необъявленные переменные. И да, хотя у интерпретатора всегда есть возможность определить (проверить) инициализирована переменная уже или нет, речь идет об оптимизации компилятора, определяющей, нужна такая проверка или нет. Что не разрешимо. - person Bergi; 11.04.2017
comment
Есть ошибка \ неправильная реализация и неправильное поведение varletconst в условной \ блочной \ локальной области видимости, препятствующее принципу поиска после неудачного просмотра, как в: function lookupDisabled(){ const myval = 1; console.log( myval ); if(myval === 1) { /*console.log( myval ); ReferenceError*/ const myval = 2; console.log( myval ); if( myval === 2 ){ /*console.log( myval ); ReferenceError*/ const myval = 3; console.log( myval );} console.log( myval ); } return myval; } где закомментированные журналы myval должны иметь возможность искать в внешний обзор лог 1. - person Bekim Bacaj; 11.04.2017
comment
Нет, это не ошибка и не ошибка. Пожалуйста, проверьте мой ответ, как это работает. И это сделано специально. - person Bergi; 11.04.2017
comment
Любое контринтуитивное, неожиданное и, следовательно, неправильное поведение; особенно те, которые противоречат фундаментальному принципу программирования данного языка, по определению и обычно считаются ошибкой. Это нарушает принцип поиска без причины. Это преждевременная и неправильная оптимизация упреждающего включения во время синтаксического анализа (которая может сэкономить несколько циклов процессора), но, тем не менее, это ошибка. Тот факт, что идентификатор данного значения ожидает объявления, не должен быть причиной для того, чтобы сделать его недоступным, особенно когда условное создание текущего контекста говорит !0. - person Bekim Bacaj; 11.04.2017
comment
Это не нарушает никакого принципа поиска. Вам просто нужно понять, что области действия вводятся с помощью блоков, а не объявлений переменных. - person Bergi; 11.04.2017