Три фазы выполнения JavaScript
Выполнение JS-кода идёт в три фазы: parsing → instantiation → execution. На фазе instantiation создаются bindings (отсюда эффект "hoisting").
Что это / Зачем
Объясняет почему:
var-переменная доступна до своего объявления (сundefined)let/constдаютReferenceErrorв TDZ- function declaration вызывается выше по коду
- Существует JIT-warmup (Ignition → TurboFan)
Три фазы
1. Parsing (Compilation)
- Лексер → AST
- Проверка синтаксиса (
SyntaxErrorздесь) - Резолв scope: для каждой функции/блока строится список deklaraций
- V8: байткод Ignition + предварительные данные для TurboFan
2. Instantiation (Creating Execution Context)
Создаётся Execution Context с Lexical Environment. Для каждого declaration:
| Declaration | Действие на этапе instantiation |
|---|---|
var x |
binding x → undefined |
function f |
binding f → готовая функция |
let x |
binding x → uninitialized (hole) |
const x |
binding x → uninitialized (hole) |
class C |
binding C → uninitialized (hole) |
3. Execution
Построчное выполнение. При обращении к идентификатору:
- Если binding = uninitialized →
ReferenceError - Если есть значение → используется
- При
let x = 5илиconst x = 5— binding инициализируется значением
Пример
console.log(a); // undefined (var = bound to undefined)
console.log(b); // ReferenceError (let = hole)
console.log(f); // ƒ f {...} (function declaration)
// console.log(g); // TypeError (g is undefined, .call on undefined)
var a = 1;
let b = 2;
function f() {}
var g = function {};
На фазе instantiation:
a→ undefinedb→ holef→ готовая функцияg→ undefined (только var-binding, не expression)
JIT-warmup в V8 (поверх 3 фаз)
После прохождения 3 фаз код исполняется Ignition (интерпретатор байткода). Если функция вызывается часто:
- Ignition собирает feedback (типы аргументов, результаты)
- При достижении threshold — TurboFan компилирует в машинный код
- Если предположения нарушаются — деоптимизация обратно в Ignition
Подводные камни
- function declaration внутри блока (не верхний уровень) ведёт себя как
letв новых движках, но какvarв legacy function f() {}иlet f = function {}— РАЗНЫЕ declarations на этапе instantiation- В strict mode правила инициализации строже (например, дубликаты параметров запрещены)
🎓 Источники
- ⚡ [⎡JSbook 04.00⎦ Как выполняется JS код] · AsForJS · 2023-09-30 · YouTube
- Тезисы: разбор execution в 3 фазах. Parsing, instantiation, execution. Каждая фаза — отдельный шаг в спеке
- ⚡ [⎡spec03⎦ Hoisting согласно спецификации] · AsForJS · 2023-11-19 · YouTube
- Тезисы: то что называют "hoisting" — это фаза instantiation. На ней создаются bindings ДО выполнения. Никакого "поднятия" в тексте программы нет
- ⚡ [⎡spec 00⎦ Call Stack согласно спецификации] · AsForJS · 2023-11-03 · YouTube
- Тезисы: Call Stack хранит Execution Context, который создаётся на фазе instantiation для каждой функции