Замыкания

Замыкание — это когда функция запоминает и сохраняет доступ к переменным из внешней области видимости, даже после того как внешняя функция завершила свою работу.

Это происходит потому, что в JavaScript каждая функция «запоминает» окружение, в котором она была создана — даже если она выполняется позже, в другом месте.

Простой пример:

function createUserManager() {
  let userCount = 0;

  return function() {
    userCount++;
    return `Пользователей: ${userCount}`;
  };
}

const addUser = createUserManager();

console.log(addUser()); // "Пользователей: 1"
console.log(addUser()); // "Пользователей: 2"
console.log(addUser()); // "Пользователей: 3"

Здесь:

  • createUserManager создаёт переменную userCount и возвращает внутреннюю функцию
  • После вызова createUserManager() внешняя функция завершается — её стек должен быть очищен
  • Но внутренняя функция (addUser) продолжает «помнить» и использовать userCount
  • Это и есть замыкание: внутренняя функция замыкает на переменную из внешней области

Пример 1: Настройки темы приложения

function createThemeManager() {
  let currentTheme = "light";

  return {
    getTheme() { return currentTheme; },
    setTheme(theme) { currentTheme = theme; },
    toggleTheme() { currentTheme = currentTheme === "light" ? "dark" : "light"; }
  };
}

const theme = createThemeManager();
theme.setTheme("dark");
console.log(theme.getTheme()); // "dark"
theme.toggleTheme();
console.log(theme.getTheme()); // "light"

Тема хранится в замыкании — не загрязняет глобальное пространство, доступна только через контролируемые методы.

Пример 2: Обработчик событий с контекстом

function setupButtonHandler(buttonId, userId) {
  document.getElementById(buttonId).addEventListener("click", function() {
    console.log(`Кнопка ${buttonId} нажата пользователем ${userId}`);
  });
}

setupButtonHandler("profileBtn", 456);
// При клике выведет: "Кнопка profileBtn нажата пользователем 456"
// Даже если функция setupButtonHandler уже завершилась — замыкание сохранило userId

Пример 3: Каррированные функции

Каррирование — это преобразование функции, принимающей несколько аргументов, в последовательность функций, каждая из которых принимает один аргумент. Основано на замыканиях.

function multiply(a) {
  return function(b) {
    return function(c) {
      return a * b * c;
    };
  };
}

const multiplyBy2 = multiply(2);
const multiplyBy2And5 = multiplyBy2(5);
console.log(multiplyBy2And5(3)); // 30

// Или в одну строку:
console.log(multiply(2)(5)(3)); // 30

Здесь каждая вложенная функция «запоминает» значение a, затем b, используя замыкание. Это позволяет создавать переиспользуемые частичные версии функций — например, для форматирования, валидации или настройки API-запросов.

Важно понимать:

  • Замыкание не создаёт копию переменной — оно ссылается на неё
  • Если переменная меняется — замыкание видит новое значение
  • Замыкания могут вызывать утечки памяти, если держат ссылки на большие объекты без необходимости

Замыкания — мощный инструмент. Используйте их для инкапсуляции данных, создания приватных состояний, управления контекстом в обработчиках и реализации каррированных функций — особенно в React, Vue или чистом JavaScript без фреймворков.