Что такое замыкания в JavaScript и для чего они нужны
Что проверяют
Понимаете ли вы, что функция помнит окружение, в котором была создана, а не то, откуда её вызвали. От этого зависит, сможете ли вы читать чужой асинхронный код и не ловить утечки памяти.
Как отвечать
Замыкание это функция вместе с её лексическим окружением: она сохраняет доступ к переменным внешней функции даже после того, как та завершилась. Область видимости определяется местом, где функция объявлена, а не местом вызова.
function createCounter() {
let count = 0; // живёт, пока жива вложенная функция
return () => ++count;
}
const next = createCounter();
next(); // 1
next(); // 2count недоступна снаружи и не пропадает между вызовами. Отсюда и практическая польза:
- приватное состояние: переменную нельзя случайно перезаписать извне;
- фабрики функций: функция с предзаданными параметрами (каррирование);
- колбэки и обработчики: они помнят контекст, в котором создавались;
- мемоизация, троттлинг, дебаунс: кэш и таймер хранятся в замыкании, а не в глобальной переменной.
Где спотыкаются
Классика с циклом: var создаёт одну переменную на весь цикл, поэтому все колбэки видят её последнее значение. let создаёт свою переменную на каждой итерации.
for (var i = 0; i < 3; i++) setTimeout(() => console.log(i)); // 3, 3, 3
for (let i = 0; i < 3; i++) setTimeout(() => console.log(i)); // 0, 1, 2Второе: замыкание держит ссылку на всё окружение, а не только на нужную переменную. Обработчик события, замкнувший тяжёлый объект и не снятый со страницы, не даёт сборщику мусора его убрать.
Третье: путают замыкание с this. Замыкание про переменные, this определяется способом вызова, и стрелочная функция берёт его из внешнего контекста как раз потому, что своего не имеет.