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, которая лежит в основе множества паттернов: модульного кода, каррирования, мемоизации и реактивного программирования. Понимание того, как функции захватывают переменные из внешних областей видимости, открывает доступ к более чистому и выразительному коду.

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

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

    Комментарии

    0

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

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

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

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

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

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

    HTML и CSS

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

    CSS Flexbox

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

    Основы JavaScript

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

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

    Картинка поста Vue vs React в 2026: какой фреймворк выбрать для проекта
    Иконка аватараАнтон
    Иконка календаря10 сентября 2026
    VueReactFrontend+ 1middleИконка уровня middle

    Vue vs React в 2026: какой фреймворк выбрать для проекта

    Сравниваем Vue и React в 2026 году: реактивность, Composition API vs хуки, Server Components и Vapor Mode на примерах кода.

    Иконка чипа0
    Иконка глаза209
    Иконка комментариев0
    Картинка поста Микросервисная архитектура для начинающих: гайд с примерами
    Иконка аватараАнтон
    Иконка календаря23 сентября 2026
    микросервисыархитектураbackend+ 2juniorИконка уровня junior

    Микросервисная архитектура для начинающих: гайд с примерами

    Микросервисная архитектура простыми словами: чем она отличается от монолита, какие есть плюсы и минусы, и как спроектировать первую систему на микросервисах — с примерами кода.

    Иконка чипа0
    Иконка глаза23
    Иконка комментариев0
    Иконка аватараАнтон
    Иконка календаря23 сентября 2026
    Claude CodeopenaiAI-инструменты+ 2middleИконка уровня middle

    Claude Code и Codex в VS Code: подключение из России

    Claude Code и Codex в VS Code ставятся из маркетплейса как любое другое расширение, и на этом штатный сценарий для России заканчивается: диалог открывается, но ответа не приходит. Причина не в редакторе — запрос не доходит до модели. Рабочее решение одно: указать расширению другой адрес API. Оба расширения умеют ходить в совместимый шлюз, и у [AI для кода от PurpleSchool](https://purpleschool.ru/ai-for-code) такой шлюз есть — ключ берётся в личном кабинете, подписка оплачивается российской картой. Ниже два маршрута настройки, для Claude Code и для Codex: конфиги целиком, построчный разбор и причины, по которым VS Code может не увидеть ключ.

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