← Назад к вопросам

Какая структура у лексического окружения?

2.0 Middle🔥 191 комментариев
#JavaScript Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Структура лексического окружения в JavaScript

Лексическое окружение (Lexical Environment) — это фундаментальная концепция в JavaScript, определяющая, как и где имена переменных и функций связаны со своими значениями в процессе выполнения кода. Его структура является внутренней деталью спецификации ECMAScript, но понимание её устройства критически важно для глубокого освоения языка, особенно замыканий и поднятия (hoisting).

Базовая структура

Каждое лексическое окружение формально состоит из двух основных компонентов:

  1. Запись окружения (Environment Record) — это внутренняя таблица (структура данных), которая хранит все связи идентификаторов (имен переменных, функций, параметров) с их текущими значениями. По сути, это "словарь" или "карта" для конкретной области видимости.
  2. Ссылка на внешнее лексическое окружение (Outer Lexical Environment Reference) — это указатель на лексическое окружение, которое является родительским по отношению к текущему. Эта ссылка образует цепочку областей видимости (Scope Chain).
// Концептуальное представление структуры LexicalEnvironment
LexicalEnvironment = {
    EnvironmentRecord: {
        // Здесь хранятся связи: идентификатор -> значение
        x: 10,
        sayHi: <function object>,
        inner: <function object>
    },
    outer: <Reference to the parent Lexical Environment> // Может быть null
}

Детализация Environment Record

Записи окружения бывают разных типов, что оптимизирует работу движка:

  • Декларативная запись окружения (Declarative Environment Record):
    *   Хранит связки, созданные объявлениями `let`, `const`, `class`, `module`, `import`, а также объявлениями функций (`function`) и генераторов (`function*`) в рамках данной области видимости.
    *   Именно здесь работает "временная мёртвая зона" (TDZ) для `let` и `const`.

  • Запись окружения объекта (Object Environment Record):
    *   Используется, когда лексическое окружение связано с объектом, например, в `with`-statement или для глобального объекта.
    *   В этом случае идентификаторы ищутся как свойства связанного объекта.

// Пример, где используется Object Environment Record (заявление with)
const myObj = { a: 1, b: 2 };
with (myObj) { // Создаётся LexicalEnvironment с Object Environment Record, связанным с myObj
    console.log(a + b); // Идентификаторы 'a' и 'b' ищутся как свойства myObj
}

Как работает цепочка областей видимости (Scope Chain)

Когда движку необходимо найти значение переменной (процесс разрешения идентификатора — Identifier Resolution), он начинает поиск в EnvironmentRecord текущего лексического окружения. Если идентификатор не найден, движок следует по ссылке outer к родительскому лексическому окружению и повторяет поиск. Этот процесс продолжается до тех пор, пока переменная не будет найдена или пока цепочка не закончится (ссылка outer станет null). На глобальном уровне внешняя ссылка равна null.

const globalVar = 'Я в глобальной области';

function outerFunc() {
    const outerVar = 'Я в outerFunc';

    function innerFunc() {
        const innerVar = 'Я в innerFunc';
        // Поиск innerVar: найдена в собственном EnvironmentRecord.
        // Поиск outerVar: не найдена локально -> идёт по outer -> найдена в EnvironmentRecord outerFunc.
        // Поиск globalVar: не найдена локально -> идёт по outer -> не найдена в outerFunc -> идёт по outer из outerFunc (глобал) -> найдена.
        console.log(innerVar, outerVar, globalVar);
    }

    innerFunc();
}

outerFunc();

Взаимосвязь с контекстом выполнения

Важно понимать, что лексическое окружение — это лишь часть контекста выполнения (Execution Context). Полный контекст выполнения включает:

  • LexicalEnvironment — определяет связывание идентификаторов, доступных по let, const, function, class и т.д.
  • VariableEnvironment — исторически для переменных, объявленных через var. В современных реализациях часто совпадает с LexicalEnvironment, но с семантическими отличиями для var.
  • Ссылка ThisBinding.

Практическое значение

Понимание этой структуры объясняет ключевые механизмы JavaScript:

  • Замыкания (Closures): Функция сохраняет ссылку на лексическое окружение, в котором она была создана, даже если выполнение покинуло эту область. Её outer ссылка продолжает указывать на "родительское" окружение, сохраняя доступ к его переменным.
  • Поднятие (Hoisting): На этапе создания контекста выполнения, до выполнения кода, EnvironmentRecord заполняется записями для всех объявлений в данной области. Для var переменным присваивается undefined, а ссылки на функции создаются сразу.

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