Что такое замыкание
Замыкание — это функция, которая запоминает своё лексическое окружение (область видимости, в которой она была создана) и сохраняет доступ к его переменным даже после того, как эта область завершила выполнение. Проще говоря, функция «замыкает» переменные, которые были в её области видимости на момент создания, и может использовать их позже, даже если вызывается из другого контекста.
Как это работает
В JavaScript функции — это объекты, и каждая функция при создании получает скрытое свойство [[Environment]], которое ссылается на текущее лексическое окружение. Когда функция вызывается, интерпретатор создаёт новое окружение выполнения, но цепочка областей видимости строится на основе [[Environment]]. Поэтому функция всегда имеет доступ к переменным из внешней области, даже если внешняя функция уже вернула результат.
Ключевой момент: замыкание образуется не в момент вызова, а в момент объявления функции. Оно фиксирует не значения переменных, а сами переменные (по ссылке). Это значит, что если внешняя переменная изменится после создания замыкания, функция увидит новое значение.
Пример
Классический пример — счётчик:
function создатьСчетчик() {
let количество = 0; // переменная замкнута внутри функции увеличить
function увеличить() {
количество += 1;
return количество;
}
return увеличить;
}
const счетчик = создатьСчетчик();
console.log(счетчик()); // 1
console.log(счетчик()); // 2Здесь увеличить продолжает видеть количество, хотя создатьСчетчик уже завершилась. Каждый вызов счетчик() изменяет одну и ту же переменную, поэтому состояние сохраняется между вызовами.
Другой пример — приватные переменные:
function создатьПользователя(имя) {
let возраст = 0;
return {
получитьИмя: () => имя,
установитьВозраст: (новыйВозраст) => { возраст = новыйВозраст; },
получитьВозраст: () => возраст
};
}
const юзер = создатьПользователя('Анна');
юзер.установитьВозраст(25);
console.log(юзер.получитьВозраст()); // 25
// переменная возраст недоступна напрямую извнеПодводные камни
- Замыкание хранит ссылку, а не значение. Если внешняя переменная меняется, замыкание видит новое значение. Это часто приводит к ошибкам в циклах, например, при использовании
varвfor. - Память. Замыкание удерживает переменные в памяти до тех пор, пока сама функция жива. Если замыкание хранится долго, это может привести к утечкам памяти, особенно при работе с большими объектами.
- Потеря контекста
this. Замыкание не сохраняетthisвнешней функции. Если внутри замыкания нужен доступ кthis, его нужно сохранить заранее (например, в переменнуюself) или использовать стрелочную функцию.
Когда использовать
Замыкания применяются для:
- инкапсуляции состояния и создания приватных переменных;
- фабрик функций, которые возвращают настроенные обработчики;
- каррирования и частичного применения аргументов;
- реализации мемоизации (кэширования результатов);
- создания модулей, скрывающих внутренние детали.
Коротко
- Замыкание — функция, которая сохраняет доступ к переменным своей лексической области видимости после её завершения.
- Механизм основан на скрытом свойстве
[[Environment]], которое хранит ссылку на внешнее окружение. - Замыкание хранит ссылку на переменные, а не их значения, поэтому изменения внешней переменной видны внутри функции.
- Используется для инкапсуляции, сохранения состояния, каррирования и создания модулей; осторожно с памятью и
this.
