11001

Lexical Environment

Каждый раз, когда в программе вызывается функция, внутри интерпретатора создается специальный словарь LexicalEnvironment (лексическое окружение), привязанный к этому вызову. (Lexical Env - abstract data structure, dictionary)

Execution context pushed to call stack

The Execution Context goes on the stack, which contains a reference to the LE, not the LE itself.

Scope Chain Resolution

When accessing a variable:

  1. Check current Environment Record

  2. If not found, follow Outer reference

  3. Repeat until found or reach null (ReferenceError)

    Execution Context contains:

    • Lexical Environment (let, const, function declarations)

    • Variable Environment (var declarations - usually same as LE)

    • this binding

      Key difference: Execution Context is runtime, Lexical Environment is the scope mechanism.

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

      Окружение — это не «все, что было объявлено до функции, в которой мы используем эти объявления». Не важно, что number появился позже использования внутри функции. Главное, что вызов функции square происходит позже определения number, а значит к этому времени идентификатор уже был добавлен в окружение, внутри которого была создана функция square.

      Когда мы работаем с константами, все просто. Нет изменений — нет проблем. В случае с переменными ситуация становится сложнее.

      Изменение переменной следует читать как «изменение значения ключа в окружении». Соответственно, обращение к number всегда вернет последнее присвоенное значение. Завязка на переменные, описанная в коде выше, должна восприниматься как абсолютное зло. Она порождает неявные зависимости, сложный код и отладку. Функция автоматически перестает быть чистой, так как начинает зависеть от внешнего контекста.

      интерпретатор производит поиск значения идентификатора не только в локальном лексическом окружении (в том, где используется идентификатор), но и во внешнем окружении. Поиск начинается с локального окружения, и если в нем не найден нужный идентификатор, то просмотр идет дальше, вплоть до уровня модуля, а затем и до глобального уровня.

Внешним окружением по отношению к функции считается окружение, в котором функция была объявлена (а не вызвана!). Если разбить пример выше на два файла, то разница станет очевидной.

Окружение есть не только у функций. Любой идентификатор, определенный на уровне модуля, попадает в лексическое окружение модуля. Кроме того, существует и глобальное окружение. Благодаря ему мы с легкостью используем в JS такие функции, как console.log или Math.sqrt, даже особо не задумываясь, откуда они берутся.

Область видимости (scope) — это широкое понятие, означающее, грубо говоря, «интерпретатор в разных местах кода видит разные штуки».

Лексическая область видимости (Lexical scoping) — это конкретный механизм, одно из правил для области видимости. Этот механизм применяется в JavaScript и большинстве других языков. Под лексической областью видимости можно понимать просто механизм поиска значений: смотрим в текущей области, если нет — идём на уровень выше, и так далее. Слово «лексический» означает, что видимость задаётся исключительно текстом программы, исходным кодом. То есть можно смотреть на программу, не запуская её, и понять область видимости в любой точке.

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

Этот механизм называется лексической областью видимости. Область видимости любого компонента определяется местом расположения этого компонента внутри кода. И вложенные блоки имеют доступ к их внешним областям видимости.

fn(a) -> it's like fn(let a) - just variable


Область видимости (scope) компонентов — это местоположение, где эти компоненты доступны.

  • Компоненты, созданные снаружи функций, инструкций с if, циклов и так далее, находятся в глобальной области видимости

  • Фигурные скобки { } задают новую локальную область видимости


    Это замыкание: сочетание функции и окружения, где она была заявлена.



Temporal Dead Zone (TDZ) - explain on browser dev tools show example
The period between entering a scope and the actual declaration where a variable exists but cannot be accessed. Accessing it throws a ReferenceError.

let, const, class has TDZ (var without TDZ, undefined)

Arrow functions follow the hoisting rules of their declaration keyword (var/let/const).
Function Declarations - Fully Hoisted


Variables exist in the Environment Record from block start but are uninitialized:
The binding exists in the LE but accessing before initialization throws an error.

// Declaration: added to LE during creation phase (hoisted)
function declared() {}

// Expression: added during execution phase
const expressed = function() {};


Golden Rule: Function declarations hoist completely, function expressions follow their declaration keyword's rules.