Skip to main content

Лексична область видимості

Лексична область видимості (lexical scope), це область, яку визначає розташування коду в момент його написання, а не момент виконання. Те, яка функція до яких змінних має доступ, вирішується на етапі оголошення, коли рушій читає початковий код, а не тоді, коли ви викликаєте функцію.

Теорія

TL;DR

  • Лексична область видимості визначається розташуванням коду в тексті програми.
  • Рішення про доступ до змінних ухвалюється на етапі оголошення та парсингу, а не під час виклику.
  • Внутрішня функція бачить змінні всіх функцій, у які вона вкладена, і глобальні змінні.
  • Пошук імені йде вгору по ланцюжку областей видимості (scope chain): inner -> outer -> global.
  • У мовах з динамічною областю видимості (Bash, старий Lisp) усе навпаки: вирішує той, хто викликав.
  • Замикання (closure), це практичний наслідок лексичної області видимості.

Швидкий приклад

javascript
let a = 10; function outer() { let b = 20; function inner() { let c = 30; console.log(a, b, c); // 10 20 30 } inner(); } outer();

Тут inner оголошено всередині outer, тому вона має доступ і до змінних outer, і до глобальних. JavaScript запам'ятав цю структуру при оголошенні, а не при виклику.

Ланцюжок областей видимості:

javascript
inner -> outer -> global

Чому саме «лексична»

Слово «лексична» (від англ. lexical) означає «та, що стосується тексту програми». Рушій «запам'ятовує» розташування функцій і блоків коду під час парсингу, коли читає початковий файл, а не тоді, коли ви викликаєте функції.

Практичний наслідок: область видимості будь-якої функції можна визначити, просто подивившись на текст файлу, не запускаючи програму. Саме тому лінтери та IDE вміють підсвічувати недосяжні або затінені змінні ще до запуску.

Лексична проти динамічної області видимості

Деякі мови (наприклад Bash або старий Lisp) використовують динамічну область видимості: її визначає той, хто викликав функцію. У JavaScript область лексична: її визначає те, де функцію написано.

javascript
let x = "global"; function foo() { console.log(x); } function bar() { let x = "local"; foo(); // хто викликав foo? bar, але... } bar();

Результат:

javascript
global

Тому що foo оголошено в глобальній області, і JavaScript шукає x саме там, а не там, звідки її викликали (bar).

Це і є суть лексичної області: «шукай там, де функцію написано, а не там, звідки її викликано».

Замикання, практичний вияв лексичної області

javascript
function makeCounter() { let count = 0; return function() { count++; console.log(count); }; } const counter = makeCounter(); counter(); // 1 counter(); // 2

Тут внутрішня функція запам'ятала лексичне оточення makeCounter і навіть після завершення зовнішньої функції все ще «бачить» count.

Це можливо лише тому, що область видимості лексична, а не динамічна: посилання на зовнішнє оточення прошите у функцію при її створенні, тож воно живе стільки, скільки живе сама функція.

Візуально

javascript
[ Global Scope ] a = 10 | [ outer() Scope ] b = 20 | [ inner() Scope ] c = 30

Функція inner завжди «знає», де шукати a і b, бо це визначено на етапі оголошення.

Підсумок

ПоняттяОпис
Лексична область видимостіОбласть, у якій функція «бачить» змінні; визначається розташуванням у початковому коді
Коли визначаєтьсяПід час написання коду, а не під час виконання
Навіщо потрібнаЩоб рушій знав, які змінні доступні кожній функції
Пов'язане зLexical Environment, Scope Chain, Closures

Типові помилки

  • Вважати, що область видимості залежить від місця виклику. Ні, лише від місця оголошення в тексті програми.
  • Очікувати, що foo() з прикладу вище побачить локальний x із bar. Це поведінка динамічної області, якої в JavaScript немає.
  • Плутати лексичну область із this. У звичайних функціях this визначається якраз динамічно, під час виклику; лексично його беруть лише стрілкові функції.
  • Думати, що після завершення зовнішньої функції її змінні гарантовано зникають. Якщо на них тримає посилання замикання, вони живуть далі.
  • Плутати лексичну область із hoisting. Hoisting відповідає на питання «коли змінна стає доступною», лексична область, на питання «де її взагалі шукати».

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.