Коротка відповідь
juniorЗамикання — це функція, що зберігає доступ до змінних свого оточення навіть після завершення виконання зовнішньої функції. Це дозволяє створювати приватні змінні, фабрики функцій і мемоізацію. Приклад: const counter = () => { let i=0; return () => ++i; }.
Повне пояснення
-
Що це і навіщо Замикання (closure) — механізм, що дозволяє функції «запам’ятовувати» контекст виконання. Це корисно для створення приватних даних, фабрик функцій і оптимізації через мемоізацію.
-
Ключові принципи/терміни
scope– лексичний контекст, у якому оголошено змінну.hoisting– підняття декларацій, що впливає на доступність.thisу замиканні залишається прив’язаним до зовнішньої функції, якщо не використаноbind/arrow.
-
Як це працює Коли внутрішня функція повертається, вона зберігає посилання на об’єкт
Environment Record, що містить всі локальні змінні зовнішньої функції. Після завершення виконання зовнішньої функції цей об’єкт не видаляється, бо на нього посилаються замикання. -
Практика і реалізація
// Фабрика логера з приватним рівнем function createLogger(level: string) { const prefix = `[${level}]`; return (msg: string) => console.log(prefix, msg); } const info = createLogger('INFO'); info('Запуск сервера'); // [INFO] Запуск сервера// Меморизація функції const memo = (fn) => { const cache = new Map(); return (...args) => { const key = JSON.stringify(args); if (cache.has(key)) return cache.get(key); const result = fn(...args); cache.set(key, result); return result; }; }; const fib = memo((n) => (n < 2 ? n : fib(n - 1) + fib(n - 2))); -
Тестування Unit – перевірка, що замикання зберігає стан:
test('counter preserves state', () => { const counter = createCounter(); expect(counter()).toBe(1); expect(counter()).toBe(2); }); -
Дизайн‑решення
- Використовувати замикання для створення приватних полів у класах, коли
#privateнедоступний. - У React hooks замикання допомагає зберігати попереднє значення у
useRef.
- Використовувати замикання для створення приватних полів у класах, коли
-
Оптимізація, типові помилки
- Перевантаження пам’яті: великі замикання з великими об’єктами можуть утримувати зайві дані.
this‑проблеми: arrow functions абоbindпотрібні, коли контекст важливий.
-
Часті помилки
- Неочікуваний доступ до змінної після її видалення: замикання зберігає посилання, тому змінна не стирається.
- Застосування замикання в циклі без
let/const: всі функції отримують одне й те саме значення.
-
Cheatsheet
const fn = () => {}– arrow, зберігаєthis.function fn() {}– звичайна функція,thisзалежить від виклику.const counter = () => { let i=0; return () => ++i; }– простий приклад приватного стану.
-
Follow‑up питання
- Як замикання впливають на збірку сміття в V8?
- Чому
setTimeout(() => console.log(i), 1000)в циклі може вестися неочікувано безlet?