ECMAScript: где можно найти спецификацию о доступности переменных let/const

В спецификации ECMAScript, где мы можем найти четкую спецификацию, почему let а также const не доступны вне Лексических Сред, созданных с помощью BlockStatements (в отличие от переменных, объявленных с var)?

Если BlockStatements теперь создают новые лексические среды, то let а также const объявления не должны создавать переменные, доступные вне этой лексической среды, но var переменные должны. Я пытаюсь понять, где именно это поведение указано в последней спецификации ECMAScript.

Из деклараций 13.3.1 Let и Const:

Объявления let и const определяют переменные, относящиеся к области Lexical Environment запущенного контекста выполнения. Переменные создаются, когда создается экземпляр их содержащей Lexical Environment, но к ним нельзя получить доступ, пока не будет оценена переменная LexicalBinding.

С 13.3.2. Переменная Заявка:

Оператор var объявляет переменные, относящиеся к области VariableEnvironment текущего контекста выполнения. Переменные var создаются, когда создается экземпляр их содержащей Lexical Environment и при создании инициализируются как неопределенные.

Как видно, оба объявления переменных создают переменные, когда создается экземпляр их содержащей Lexical Environment. Что в случае BlockStatement - это когда компилятор входит в блок.

С 8.3 Контексты исполнения:

Компоненты Lexical Environment и VariableEnvironment контекста выполнения всегда являются лексическими средами.

1 ответ

Решение

Как вы видели в описании var, он ограничен контекстом выполнения VariableEnvironment, Есть верхний уровень VariableEnvironment и затем создается новая, когда вы вводите функцию, а затем в этой части о контекстах выполнения она говорит следующее:

Компоненты LexicalEnvironment и VariableEnvironment контекста выполнения всегда являются лексическими средами. Когда создается контекст выполнения, его компоненты LexicalEnvironment и VariableEnvironment изначально имеют одинаковое значение.

Итак, в начале функции LexicalEnvironment и VariableEnvironment являются одним и тем же.

Затем в разделе 13.2.13 Семантика времени выполнения: блок оценки: { } вы можете увидеть, что новый LexicalEnvironment создается при входе в блок, а предыдущий восстанавливается при выходе из блока. Но нет никакого упоминания о новом VariableEnvironment когда вы входите или выходите из блока (потому что он остается постоянным внутри функции).

Итак, с let а также const находятся в области LexicalEnvironment, в которой они объявлены и являются локальными для блока, он не будет доступен за пределами блока.

Но, var относится к VariableEnvironment который создается только для всей функции, а не для блока.

let а также const переменные не могут быть доступны вне их LexicalEnvironment, потому что их определения не находятся в иерархии областей действия, как только контекст выполнения покидает их блок (как только вы покидаете блок, их LexicalEnvironment по существу выталкивается из стека и больше не находится в область поиска цепочки для интерпретатора, чтобы найти переменные).


Когда спецификация добавляет это:

[ let а также const ] переменные создаются, когда создается экземпляр их содержащей Lexical Environment, но к ним нельзя получить доступ каким-либо образом, пока не будет оценена переменная LexicalBinding.

Это означает, что вам отказано в доступе к ним даже в их собственной лексической среде, пока их определение не будет оценено. С точки зрения непрофессионала, это означает, что они не подняты к вершине их объема как var и, следовательно, не может быть использовано до тех пор, пока не будет определено их. Это реализуется путем не инициализации let или же const переменная в LexicalEnvironment пока его заявление не работает и GetBindingValue() Операция, которая ищет переменную, увидит, что она еще не инициализирована, и выдаст ReferenceError, var переменные инициализируются немедленно undefined поэтому они не вызывают это ReferenceError,

Вы можете увидеть, как это работает в этом коде:

let x = 3;

function test() {
    x = 1;
    let x = 2;
    console.log("hello");
}
test();

На let x = 3 строка переменная x инициализируется во внешнем LexicalEnvironment.

Затем, когда вы звоните test() в начале этой функции создается новое LexicalEnvironment, новое объявление для x в этом блоке помещается в этот новый LexicalEnvironment, но еще не инициализирован.

Затем вы получите к x = 1 заявление. Переводчик смотрит вверх x, находит его в текущем LexicalEnvironment, но он неинициализирован, поэтому он бросает ReferenceError,


На вопрос в вашем комментарии:

Я переворачивал спецификацию с ног на голову, но с трудом обнаружил, что VariableEnvironments создаются только для функций. Не могли бы вы добавить ответ, показывающий, какие шаги в спецификации вы выполняете, чтобы прийти к такому выводу?

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

Например, вот один из тех мест: PrepareForOrdinaryCall. Есть несколько других.

Но нигде не описано, что это происходит для начала блока, только для начала функции.

То, как эти спецификации написаны, они описывают, когда что-то происходит, а не когда это не происходит (что имеет некоторый логический смысл), но это значит, что доказать, что что-то не происходит, вы не можете найти то, что говорит это действительно случается.

Другие вопросы по тегам