Skip to main content

Користь від замикань

Що таке замикання

Замикання - це функція, яка "пам'ятає" лексичну (зовнішню) область, навіть якщо вона виконується поза цією областю.

Простіше кажучи:

Замикання - це здатність функції дістатися до змінних з місця, де вона була створена, а не звідти, де вона викликана.


Приклад 1 - базовий

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

Що відбувається:

  • outer() повертає inner();
  • inner() запам'ятав змінну count зі свого лексичного оточення;
  • навіть після того як outer() завершилася, count не зникає;
  • це і є замикання - "збережена пам'ять" функції.

Приклад 2 - приватні змінні

javascript
function createUser(name) { let score = 0; return { getName() { return name; }, addScore() { score++; }, getScore() { return score; } }; } const alice = createUser('Alice'); alice.addScore(); alice.addScore(); console.log(alice.getName(), alice.getScore()); // Alice 2

Тут score - приватна змінна: вона недоступна ззовні (alice.score не існує), але доступна із замикань getScore і addScore.

Так реалізуються інкапсуляція і приватні дані без класів.


Приклад 3 - генератори функцій (фабрики)

javascript
function makeMultiplier(factor) { return function(num) { return num * factor; }; } const double = makeMultiplier(2); const triple = makeMultiplier(3); console.log(double(5)); // 10 console.log(triple(5)); // 15

factor "живе" всередині кожної функції. Тобто кожна функція "пам'ятає", з яким множником її створили.


Приклад 4 - обробники подій

javascript
function setupButton(id) { let clicks = 0; document.getElementById(id).addEventListener('click', () => { clicks++; console.log(`Клік по кнопці ${id}: ${clicks}`); }); } setupButton('save'); setupButton('cancel');

Кожен обробник "пам'ятає" свою змінну clicks, навіть після виходу з setupButton.


Приклад 5 - кешування (memoization)

javascript
function memoize(fn) { const cache = {}; return function(arg) { if (cache[arg]) { console.log('З кешу:', arg); return cache[arg]; } const result = fn(arg); cache[arg] = result; console.log('Обчислено:', arg); return result; }; } const square = memoize(x => x * x); square(4); // Обчислено: 4 square(4); // З кешу: 4

cache зберігається між викликами завдяки замиканню.


Як це працює "під капотом"

Коли функція створюється, JS формує лексичне оточення (Lexical Environment) - об'єкт, де зберігаються всі змінні, оголошені всередині.

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

Тому навіть після завершення зовнішньої функції внутрішні функції можуть звертатися до її змінних.


Замикання створюються автоматично

Не потрібно робити нічого особливого - щоразу, коли ти створюєш функцію всередині іншої, JS створює замикання.

javascript
function outer() { const a = 42; return function() { console.log(a); // замикання }; }

Де застосовуються замикання в реальному житті

СценарійПриклад
Приватні даніХоваємо змінні всередині функції
Фабрики функційГенератори, конфігуровані обробники
Модулі та інкапсуляціяРозділення логіки без глобальних змінних
Кешування (memoization)Зберігаємо результати обчислень
Лічильники і станУтримуємо стан між викликами
Callback-и та обробники подійДоступ до зовнішніх даних всередині функції
Функціональне програмуванняCurrying, partial application, compose тощо

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

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

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