Як працюють замикання в JavaScript: прості приклади
04.03.2026Що таке замикання і чому воно важливе
Замикання в JavaScript — це можливість функції зберігати доступ до лексичного оточення, навіть якщо сама зовнішня функція вже завершила виконання. Іншими словами, функція, створена всередині іншої функції, «памятає» змінні тієї зовнішньої функції. Ця властивість дає потужні інструменти для інкапсуляції стану, створення фабрик функцій і роботи з асинхронним кодом.
Простий приклад замикання
Розглянемо базовий приклад, де внутрішня функція читає значення змінної зовнішньої функції:
function createCounter() {
let count = 0;
return function() {
count += 1;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
Функція createCounter повертає іншу функцію, яка має доступ до змінної count навіть після завершення createCounter. Це і є замикання.
Практичні застосування
- Інкапсуляція приватного стану замість використання глобальних змінних.
- Фабрики функцій, які налаштовують поведінку, наприклад, генератори обробників подій та конфігуровані функції форматування.
- Зберігання контексту для асинхронних викликів, наприклад callback або setTimeout.
Поширені помилки та як їх уникнути
Проблеми з циклами і var
Одна з типових пасток — використання var у циклах при створенні функцій. Через функціональний рівень видимості всі ітерації можуть розділяти одну змінну, що призводить до неочікуваних результатів:
for (var i = 0; i < 3; i++) {
setTimeout(function() { console.log(i); }, 100);
}
// Виведе 3, 3, 3
Рішення: використовувати let або створювати додаткове замикання для збереження поточного значення:
for (let i = 0; i < 3; i++) {
setTimeout(function() { console.log(i); }, 100);
}
// Виведе 0, 1, 2
// Або так:
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(function() { console.log(j); }, 100);
})(i);
}
Не плутайте замикання з класами
Замикання часто використовують для створення приватних змінних; це альтернативний підхід до використання класів і приватних полів. Обидва підходи мають свої плюси і мінуси. Якщо потрібна багатофункціональна структура з багатьма методами, клас може бути зручнішим. Для простої інкапсуляції стану замикання — легкий та зрозумілий варіант.
Оптимізація і проблеми з памятаю
Замикання утримує посилання на змінні оточення, тому у великих додатках треба стежити, щоб випадково не зберігати великі обєкти або DOM-елементи через замикання, коли вони більше не потрібні. Це може призвести до росту використання памяті. Дотримуйтеся простих правил:
- Звільняйте посилання на великі об’єкти, якщо вони більше не потрібні.
- Уникати зберігання великого DOM-стану в змінних замикання.
- Перевіряйте інструменти профілювання пам’яті для виявлення витоків.
Поради для читабельності і тестування
Щоб код із замиканнями був зрозумілим і тестованим, дотримуйтеся кількох практик:
- Чітко називайте фабрики функцій і змінні, які зберігають стан.
- Не захаращуйте одне замикання занадто великою кількістю відповідальностей.
- Пишіть модульні тести для функцій-фабрик, перевіряючи поведінку стану в різних сценаріях.
Висновок
Замикання — один з фундаментальних механізмів JavaScript, який відкриває багато можливостей для інкапсуляції, конфігурованих фабрик функцій і управління асинхронністю. Розуміння лексичного оточення і типових пасток, як от цикл із var, допоможе писати більш надійний і читабельний код. Використовуйте замикання навмисно: коли потрібна інкапсуляція або збереження контексту, але уникати тривалого зберігання великих об’єктів у замиканнях, щоб не створювати витоків пам’яті.