PassFront
  1. PassFront
  2. База знаний
  3. Структурные паттерны

Как устроен паттерн «Модуль» в JavaScript: инкапсуляция через замыкания и ES-модули?

Структурные паттерны

«Модуль» прячет детали реализации и открывает только публичный API: исторически — через IIFE и замыкание, сегодня — через ES-модули, где всё неэкспортированное приватно.

IIFE и Revealing Module

  • До ES2015 в браузере не было модулей: всё попадало в глобальную область, скрипты конфликтовали именами.
  • (function () { ... })() создаёт замыкание, возвращаемый объект — публичный API.
  • Revealing Module: всё объявлено приватно, в конце возвращается объект со ссылками на нужные функции.

ES-модули

  • Статические import/export → анализ зависимостей до выполнения и tree shaking.
  • Модуль исполняется один раз и кэшируется, поэтому его состояние — фактически синглтон в пределах приложения.
  • Импорты — живые привязки только для чтения: изменения внутри модуля видны снаружи, присвоить импорту нельзя. В CommonJS const { count } = require() копирует значение.
// counter.js
let count = 0; // не экспортируем напрямую — снаружи не изменить
export function increment() {
  return ++count;
}
export { count };

// main.js
import { count, increment } from './counter.js';
increment();
console.log(count); // 1 — live binding

Подводные камни

  • Состояние модуля — скрытый глобал: мешает тестам (jest.resetModules) и SSR, где один модуль обслуживает запросы разных пользователей.
  • Циклические импорты: обращение к let/const до инициализации даёт ReferenceError (TDZ).

Коротко для собеседования

Модуль открывает наружу только нужный API, а остальное держит приватным: раньше через IIFE и замыкание, сейчас через ES-модули. Состояние модуля живёт в одном экземпляре на приложение, поэтому для независимых копий экспортируют фабрику, а не готовое состояние.

Другие вопросы раздела