Разберите следующий JavaScript-фрагмент: console.log(a); var a = 5; function f(){ console.log(b); let b = 3; } f(); Объясните, что выведется, почему, и какие языковые механизмы (hoisting, temporal dead zone) за этим стоят
Выведется так: - сначала в консоль попадёт `undefined`; - затем при выполнении `f()` произойдёт ошибка `ReferenceError: Cannot access 'b' before initialization`. Почему — пошагово и какие механизмы влияют: 1. Hoisting (фаза создания контекста): - Объявление `var a` поднимается и инициализируется значением `undefined` до выполнения кода, поэтому до присвоения `a = 555` переменная существует и равна `undefined`. - Объявление функции `f` целиком (код функции) тоже поднимается — функция доступна до её текстового места в коде. - Объявления `let`/`const` (например, `let b`) тоже поднимаются, но не инициализируются — они находятся в temporal dead zone (TDZ) до выполнения строки объявления. 2. Выполнение: - Выполняется `console.log(a);` — печатает `undefined` (потому что `a` пока `undefined`). - Затем выполняется присвоение `a = 555`. - Вызывается `f()`. При входе в исполнение функции переменная `b`, объявленная через `let b = 333`, ещё в TDZ до её объявления/инициализации. Поэтому строка `console.log(b);`, стоящая до `let b = 333`, пытается получить доступ к `b` в TDZ и выбрасывает `ReferenceError`. Кратко о механизмах: - var: hoisted + инициализировано `undefined` (function/global scoped). - function declaration: hoisted вместе с телом. - let/const: hoisted, но не инициализированы до объявления — TDZ; доступ до объявления вызывает ReferenceError. Замечание: если бы `b` был объявлен через `var`, то внутри `f` `console.log(b)` вывел бы `undefined` (а не ReferenceError), потому что `var b` инициализируется как `undefined` при hoisting. Если `console.log(b)` стоял после `let b = 333`, он вывел бы `333`.
- сначала в консоль попадёт `undefined`;
- затем при выполнении `f()` произойдёт ошибка `ReferenceError: Cannot access 'b' before initialization`.
Почему — пошагово и какие механизмы влияют:
1. Hoisting (фаза создания контекста):
- Объявление `var a` поднимается и инициализируется значением `undefined` до выполнения кода, поэтому до присвоения `a = 555` переменная существует и равна `undefined`.
- Объявление функции `f` целиком (код функции) тоже поднимается — функция доступна до её текстового места в коде.
- Объявления `let`/`const` (например, `let b`) тоже поднимаются, но не инициализируются — они находятся в temporal dead zone (TDZ) до выполнения строки объявления.
2. Выполнение:
- Выполняется `console.log(a);` — печатает `undefined` (потому что `a` пока `undefined`).
- Затем выполняется присвоение `a = 555`.
- Вызывается `f()`. При входе в исполнение функции переменная `b`, объявленная через `let b = 333`, ещё в TDZ до её объявления/инициализации. Поэтому строка `console.log(b);`, стоящая до `let b = 333`, пытается получить доступ к `b` в TDZ и выбрасывает `ReferenceError`.
Кратко о механизмах:
- var: hoisted + инициализировано `undefined` (function/global scoped).
- function declaration: hoisted вместе с телом.
- let/const: hoisted, но не инициализированы до объявления — TDZ; доступ до объявления вызывает ReferenceError.
Замечание: если бы `b` был объявлен через `var`, то внутри `f` `console.log(b)` вывел бы `undefined` (а не ReferenceError), потому что `var b` инициализируется как `undefined` при hoisting. Если `console.log(b)` стоял после `let b = 333`, он вывел бы `333`.