← Назад к списку
ТехническаяFrontendJunior

Что такое замыкание (closure) и где оно применяется на практике?

Короткий ответ

  • Замыкание — функция плюс её лексическое окружение
  • Функция помнит переменные места, где была создана
  • Переменные живут, пока на них ссылается функция
  • Применение: приватное состояние, счётчики, фабрики функций
  • На замыканиях построены debounce, throttle, мемоизация
  • Каррирование и частичное применение — тоже замыкания
  • Неосторожные замыкания могут удерживать память

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

Как сказать вслух

пример ответа

Замыкание — это когда функция запоминает переменные того места, где её создали, и может пользоваться ими позже, даже если внешняя функция уже завершилась. Простой пример — счётчик: внешняя функция хранит число, а возвращает функцию, которая его увеличивает. Снаружи к этому числу доступа нет, получается приватное состояние. На этом же принципе работают debounce и мемоизация.

Подробный ответ

Основной ответ

При создании функция сохраняет ссылку на лексическое окружение — цепочку областей видимости, в которых она была объявлена. Когда функцию вызывают позже и в другом месте, она по-прежнему разрешает имена переменных через эту цепочку. Поэтому переменные внешней функции не уничтожаются после её возврата, пока на них ссылается хотя бы одно замыкание. Это даёт инкапсуляцию: состояние доступно только через возвращённые функции. Типичные применения — счётчики и генераторы id, фабрики обработчиков, debounce/throttle (хранят id таймера), мемоизация (хранит кэш), модульный паттерн до появления ES-модулей. Обратная сторона — замыкание удерживает всё окружение от сборки мусора, что иногда приводит к утечкам, например в забытых обработчиках событий.

Ключевые моменты

  • Лексическая область. Доступные переменные определяются местом объявления функции, а не местом вызова.
  • Жизнь переменных. Окружение живёт, пока на него ссылается функция; это и фича, и источник утечек памяти.
  • Инкапсуляция. Замыкание — стандартный способ сделать приватное состояние без классов и полей с #.
  • Основа утилит. debounce, throttle, once, memoize — все хранят внутреннее состояние именно в замыкании.

Практический контекст

Интервьюер почти всегда просит не определение, а живой пример: написать makeCounter или объяснить, что выведет цикл с колбэками. В ежедневной работе замыкания везде — каждый обработчик в React-компоненте замыкает пропсы и состояние своего рендера, отсюда известная проблема «устаревшего замыкания» (stale closure) в useEffect и setInterval. Умение это объяснить отличает понимание от заученного определения.

Пример кода

function makeCounter() {
  let count = 0; // приватное состояние
  return () => ++count;
}
const inc = makeCounter();
inc(); // 1
inc(); // 2
const other = makeCounter();
other(); // 1 — у каждого счётчика своё окружение

Частые ошибки

  • Дают определение, но не могут написать простейший счётчик на замыкании
  • Не знают, что каждый вызов внешней функции создаёт независимое окружение
  • Не связывают замыкания с реальными проблемами вроде stale closure в React

ИП Кочкин Алексей Сергеевич · ИНН 390509026279 · ОГРНИП 325390000030973 · jiniys2005@yandex.ru