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

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

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

    Комментарии

    0

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

    TypeScript с нуля - полный курс и паттерны проектирования — часть карты развития Frontend, Backend, Mobile

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

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

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

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

    React и Redux Toolkit

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

    Zustand

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

    Neovim

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

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

    Картинка поста Регулярные выражения в JavaScript: полное руководство
    Иконка аватараАнтон
    Иконка календаря06 августа 2026
    JavaScriptрегулярные выраженияregexp+ 2middleИконка уровня middle

    Регулярные выражения в JavaScript: полное руководство

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

    Иконка чипа0
    Иконка глаза105
    Иконка комментариев0
    Картинка поста React useState и useEffect: полное руководство 2024
    Иконка аватараАнтон
    Иконка календаря29 июля 2026
    ReactuseStateuseEffect+ 3juniorИконка уровня junior

    React useState и useEffect: полное руководство 2024

    Разбираем useState и useEffect с нуля: как управлять состоянием и побочными эффектами в React-компонентах с реальными примерами.

    Иконка чипа0
    Иконка глаза681
    Иконка комментариев0
    Картинка поста Async await в JavaScript: подробный разбор с примерами
    Иконка аватараАнтон
    Иконка календаря19 июля 2026
    JavaScriptasync/awaitасинхронность+ 3middleИконка уровня middle

    Async await в JavaScript: подробный разбор с примерами

    Разбираем async/await в JavaScript с нуля: как работает синтаксис, обработка ошибок через try/catch, параллельные запросы с Promise.all и частые ошибки

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