PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Замыкания в JavaScript: полное руководство с примерами

    Замыкания в JavaScript: полное руководство с примерами

    Аватар автора Замыкания в JavaScript: полное руководство с примерами

    Антон Ларичев

    Иконка календаря25 июня 2026
    JavaScriptзамыканияосновы JSфункцииscopejuniorИконка уровня junior
    Картинка поста Замыкания в JavaScript: полное руководство с примерами

    Введение

    Замыкания — одна из тех концепций JavaScript, которая пугает новичков, но становится незаменимым инструментом в руках опытного разработчика. В этой статье разберём, что такое замыкание, как оно работает «под капотом» и когда его использовать на практике.

    Что такое замыкание

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

    Звучит сложно? Давайте на примере:

    function создатьСчётчик() {
      // переменная живёт во внешней области видимости
      let счёт = 0;
    
      return function() {
        счёт += 1;
        return счёт;
      };
    }
    
    const счётчик = создатьСчётчик();
    console.log(счётчик()); // 1
    console.log(счётчик()); // 2
    console.log(счётчик()); // 3
    

    Функция, которую возвращает создатьСчётчик, «захватывает» переменную счёт. Каждый вызов увеличивает её значение, и оно сохраняется между вызовами — хотя создатьСчётчик давно отработала.

    Как работает область видимости

    Чтобы понять замыкания, нужно разобраться с областями видимости (scope).

    В JavaScript каждая функция создаёт свою область видимости. Переменные, объявленные внутри функции, недоступны снаружи. Но вложенная функция видит переменные родительской:

    function внешняя() {
      const сообщение = 'Привет';
    
      function внутренняя() {
        // внутренняя видит переменные родителя
        console.log(сообщение);
      }
    
      внутренняя();
    }
    
    внешняя(); // Привет
    

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

    Замыкание на практике

    Инкапсуляция данных

    Замыкания позволяют скрыть данные от внешнего мира — аналог приватных полей класса:

    function создатьКошелёк(начальныйБаланс) {
      let баланс = начальныйБаланс;
    
      return {
        пополнить(сумма) {
          баланс += сумма;
          console.log(`Баланс: ${баланс}`);
        },
        снять(сумма) {
          if (сумма > баланс) {
            console.log('Недостаточно средств');
            return;
          }
          баланс -= сумма;
          console.log(`Баланс: ${баланс}`);
        },
        проверить() {
          return баланс;
        }
      };
    }
    
    const кошелёк = создатьКошелёк(1000);
    кошелёк.пополнить(500); // Баланс: 1500
    кошелёк.снять(200);     // Баланс: 1300
    // прямого доступа к переменной баланс нет — только через методы
    

    Функции-фабрики

    Замыкания удобны для создания похожих функций с разными начальными параметрами:

    function создатьМножитель(множитель) {
      // множитель захватывается в замыкание
      return function(число) {
        return число * множитель;
      };
    }
    
    const удвоить = создатьМножитель(2);
    const утроить = создатьМножитель(3);
    
    console.log(удвоить(5));  // 10
    console.log(утроить(5)); // 15
    

    Мемоизация

    Замыкание может хранить кэш результатов дорогостоящих вычислений:

    function мемоизировать(fn) {
      const кэш = {}; // кэш живёт в замыкании
    
      return function(аргумент) {
        if (кэш[аргумент] !== undefined) {
          console.log('Из кэша');
          return кэш[аргумент];
        }
        кэш[аргумент] = fn(аргумент);
        return кэш[аргумент];
      };
    }
    
    const кешированноеВозведение = мемоизировать((n) => n * n);
    
    console.log(кешированноеВозведение(4)); // 16
    console.log(кешированноеВозведение(4)); // Из кэша → 16
    

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

    Замыкание в цикле с var

    Классическая ловушка для новичков:

    // Неправильно: все функции захватывают одну и ту же переменную i
    for (var i = 0; i < 3; i++) {
      setTimeout(function() {
        console.log(i); // выведет 3, 3, 3
      }, 1000);
    }
    
    // Правильно: let создаёт новую переменную для каждой итерации
    for (let i = 0; i < 3; i++) {
      setTimeout(function() {
        console.log(i); // выведет 0, 1, 2
      }, 1000);
    }
    

    Проблема с var в том, что он не создаёт новую переменную на каждой итерации — все колбэки ссылаются на одну i. К моменту срабатывания таймаута цикл завершился, и i равно 3. let решает проблему, создавая отдельный экземпляр для каждой итерации.

    Утечки памяти

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

    function проблемнаяФункция() {
      // тяжёлые данные в родительской области
      const большойМассив = new Array(1000000).fill('данные');
    
      return function() {
        // замыкание удерживает большойМассив в памяти, хотя не использует
        return 'Привет';
      };
    }
    
    const утечка = проблемнаяФункция();
    // большойМассив не будет очищен сборщиком мусора
    

    Решение: не объявляйте тяжёлые данные там, где они не нужны замыканию, или обнуляйте переменную явно после использования.

    Неожиданное разделение состояния

    function создатьПриветствие(имя) {
      let сообщение = `Привет, ${имя}!`;
    
      return {
        показать() {
          console.log(сообщение);
        },
        изменить(новоеИмя) {
          // все методы разделяют одну захваченную переменную
          сообщение = `Привет, ${новоеИмя}!`;
        }
      };
    }
    
    const привет = создатьПриветствие('Иван');
    привет.показать();         // Привет, Иван!
    привет.изменить('Мария');
    привет.показать();         // Привет, Мария!
    

    Это не всегда ошибка, но важно помнить: все методы объекта, созданного через замыкание, разделяют одно и то же захваченное состояние.

    Заключение

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

    Главное запомнить: замыкание — это не магия. Это функция, которая помнит среду, в которой была создана. Начните применять их в небольших задачах — счётчики, фабрики, кэширование — и вы быстро почувствуете их силу.

    Иконка глаза2

    Комментарии

    0

    Постройте личный план изучения Основы разработки до уровня Middle — бесплатно!

    Основы разработки — часть карты развития Frontend, Backend, Mobile

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Основы Git

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    HTML и CSS

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    CSS Flexbox

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    бесплатно
    Подробнее

    Похожие статьи

    Картинка поста WebSocket: что это и как работает в реальных проектах
    Иконка аватараАнтон
    Иконка календаря24 июня 2026
    websocketjavascriptnodejs+ 3juniorИконка уровня junior

    WebSocket: что это и как работает в реальных проектах

    WebSocket — протокол двусторонней связи в реальном времени. Разбираем, как устроено соединение изнутри, и пишем чат на Node.js с нуля.

    Иконка чипа0
    Иконка глаза46
    Иконка комментариев0
    Картинка поста Git rebase vs merge: когда и как правильно выбирать
    Иконка аватараАнтон
    Иконка календаря23 июня 2026
    gitrebasemerge+ 2middleИконка уровня middle

    Git rebase vs merge: когда и как правильно выбирать

    Git rebase и merge решают одну задачу, но по-разному. Разбираем отличия, сценарии применения и типичные ошибки при работе с ветками.

    Иконка чипа0
    Иконка глаза93
    Иконка комментариев0
    Картинка поста Что такое REST API и как его правильно проектировать
    Иконка аватараАнтон
    Иконка календаря22 июня 2026
    REST APIHTTPbackend+ 2juniorИконка уровня junior

    Что такое REST API и как его правильно проектировать

    REST API — архитектурный стиль для взаимодействия клиента и сервера. Разбираем принципы REST, HTTP-методы, проектирование маршрутов и типичные ошибки.

    Иконка чипа0
    Иконка глаза106
    Иконка комментариев0
    Иконка чипа0