Складові контексту виконання
Контекст виконання (Execution Context) у JavaScript складається з трьох основних компонентів: це внутрішні структури, які рушій створює для роботи вашого коду. Кожен контекст, глобальний чи функції, містить Variable Environment, Lexical Environment і This Binding.
Теорія
TL;DR
- Variable Environment (VE): оголошення через
varіfunction. - Lexical Environment (LE): оголошення через
letіconstплюс посилання на зовнішнє оточення. - This Binding: значення
this, визначається способом виклику функції. - Ланцюжок
OuterEnvironmentReferenceутворює scope chain і робить можливими замикання (closures). - Обидва оточення мають свій Environment Record, тому
varіletживуть у різних записах одного контексту.
Швидкий приклад
let x = 10;
function outer() {
let y = 20;
function inner() {
let z = 30;
console.log(x, y, z); // 10 20 30
}
inner();
}
outer();Lexical Environment функції inner() містить:
- власну змінну
z; - посилання на оточення
outer()(де єy); - і через нього посилання на глобальне оточення (де є
x).
Саме Lexical Environment робить можливими замикання (closures).
Variable Environment
Зберігає змінні й функції, оголошені через var і function (не let/const).
- Визначається під час створення контексту.
- Використовується для ініціалізації змінних і функцій.
- Доступний лише всередині поточного контексту.
Приклад:
function test() {
var a = 10;
function inner() {}
}Тут a та inner, це частина Variable Environment функції test.
Lexical Environment
Відповідає за пошук змінних і за замикання. Зберігає:
- змінні, оголошені через
letіconst; - посилання на зовнішні оточення (outer lexical environment reference);
- саму функцію як «лексичне оточення».
Це можна уявляти як «ланцюжок областей видимості» (scope chain): якщо імені немає в поточному записі, пошук іде на рівень вище, і так до глобального оточення.
This Binding
Визначає, на який об'єкт посилається this у цьому контексті. Залежить від того, як викликано функцію:
| Спосіб виклику | Значення this |
|---|---|
| Глобально (у браузері) | window |
| У функції (строгий режим) | undefined |
| У методі об'єкта | сам об'єкт |
Через call, apply, bind | значення, передане вручну |
| У стрілковій функції | береться із зовнішнього контексту |
Приклад:
const obj = {
name: "Tim",
show() {
console.log(this.name);
}
};
obj.show(); // this = obj, тому "Tim"Зведена структура
Кожен контекст виконання виглядає приблизно так:
Execution Context {
LexicalEnvironment: {
EnvironmentRecord: { let, const },
OuterEnvironmentReference: <посилання на зовнішнє LE>
},
VariableEnvironment: {
EnvironmentRecord: { var, function },
OuterEnvironmentReference: <посилання на зовнішнє LE>
},
ThisBinding: <значення this>
}Приклад візуально
let a = 1;
function outer() {
var b = 2;
function inner() {
let c = 3;
console.log(a, b, c);
}
inner();
}
outer();Коли викликається inner():
-
Створюється новий Execution Context, який містить:
- Variable Environment:
[] - Lexical Environment:
{ c: 3 } - This Binding:
undefined(строгий режим)
- Variable Environment:
-
Він має Outer Environment Reference, що веде до
outer, а звідти до глобального оточення, і саме це дозволяє знайтиbтаa.
Типові помилки
- Думати, що
letіconstживуть у Variable Environment. Вони потрапляють у Lexical Environment; VE тримає лишеvarі оголошення функцій. - Вважати, що
letне піднімається (hoisting). Піднімається, але до рядка оголошення перебуває в temporal dead zone, і звернення до нього кидаєReferenceError. - Плутати This Binding із лексичним оточенням. Стрілкова функція взагалі не має власного
this, вона бере його із зовнішнього контексту. - Думати, що scope chain будується під час виклику. Посилання
OuterEnvironmentReferenceвизначається місцем оголошення функції в коді, а не тим, звідки її викликали. - Забувати про строгий режим. У модулях і в класах код завжди строгий, тому
thisу звичайному виклику функції будеundefined, а неwindow.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.