Ответ
Замыкание — это функция, которая «запоминает» лексическое окружение (переменные, параметры), в котором она была создана, даже после того, как это внешнее окружение завершило своё выполнение. Это фундаментальная концепция JavaScript, возникающая благодаря тому, что функции являются объектами первого класса и имеют доступ к области видимости (scope) родительской функции.
Практический пример:
function createCounter() {
let count = 0; // Приватная переменная, инкапсулированная замыканием
return {
increment: function() {
count += 1;
return count;
},
decrement: function() {
count -= 1;
return count;
},
getValue: function() {
return count;
}
};
}
const myCounter = createCounter();
console.log(myCounter.getValue()); // 0
console.log(myCounter.increment()); // 1
console.log(myCounter.increment()); // 2
console.log(myCounter.decrement()); // 1
// Переменная `count` напрямую недоступна извне, защищена замыканием.
Ключевые аспекты и применение:
- Создание приватного состояния: Как показано в примере выше, замыкание позволяет эмулировать приватные поля, скрывая данные от глобальной области видимости.
- Фабрики функций и каррирование: Позволяет создавать специализированные функции на основе общего шаблона.
function multiplier(factor) { return function(x) { return x * factor; }; } const double = multiplier(2); const triple = multiplier(3); console.log(double(5)); // 10 console.log(triple(5)); // 15 - Работа с асинхронным кодом и обработчиками событий: Частая причина появления замыканий — сохранение контекста переменной внутри колбэка.
function setupButtons() { for (var i = 0; i < 3; i++) { // Использование let вместо var решает классическую проблему, // так как let создаёт новую привязку для каждой итерации. let buttonId = i; document.getElementById(`btn-${i}`).addEventListener('click', function() { console.log(`Нажата кнопка ${buttonId}`); // Замыкание захватывает buttonId }); } }
Важное замечание: Замыкание хранит ссылку на внешнюю переменную, а не её значение на момент создания. Это может приводить к неочевидному поведению в циклах (с var, как в старом примере выше) и требует внимания к управлению памятью, так как ссылки могут препятствовать сборке мусора.