Користь від замикань
Що таке замикання
Замикання - це функція, яка "пам'ятає" лексичну (зовнішню) область, навіть якщо вона виконується поза цією областю.
Простіше кажучи:
Замикання - це здатність функції дістатися до змінних з місця, де вона була створена, а не звідти, де вона викликана.
Приклад 1 - базовий
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 - приватні змінні
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 - генератори функцій (фабрики)
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)); // 15factor "живе" всередині кожної функції.
Тобто кожна функція "пам'ятає", з яким множником її створили.
Приклад 4 - обробники подій
function setupButton(id) {
let clicks = 0;
document.getElementById(id).addEventListener('click', () => {
clicks++;
console.log(`Клік по кнопці ${id}: ${clicks}`);
});
}
setupButton('save');
setupButton('cancel');Кожен обробник "пам'ятає" свою змінну clicks,
навіть після виходу з setupButton.
Приклад 5 - кешування (memoization)
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); // З кешу: 4cache зберігається між викликами завдяки замиканню.
Як це працює "під капотом"
Коли функція створюється, JS формує лексичне оточення (Lexical Environment) - об'єкт, де зберігаються всі змінні, оголошені всередині.
Якщо внутрішня функція використовує змінні із зовнішньої області, вона запам'ятовує посилання на це оточення.
Тому навіть після завершення зовнішньої функції внутрішні функції можуть звертатися до її змінних.
Замикання створюються автоматично
Не потрібно робити нічого особливого - щоразу, коли ти створюєш функцію всередині іншої, JS створює замикання.
function outer() {
const a = 42;
return function() {
console.log(a); // замикання
};
}Де застосовуються замикання в реальному житті
| Сценарій | Приклад |
|---|---|
| Приватні дані | Ховаємо змінні всередині функції |
| Фабрики функцій | Генератори, конфігуровані обробники |
| Модулі та інкапсуляція | Розділення логіки без глобальних змінних |
| Кешування (memoization) | Зберігаємо результати обчислень |
| Лічильники і стан | Утримуємо стан між викликами |
| Callback-и та обробники подій | Доступ до зовнішніх даних всередині функції |
| Функціональне програмування | Currying, partial application, compose тощо |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.