Revealing Module Pattern
Revealing Module Pattern — вариант Module Pattern, при котором весь код (приватный и публичный) объявляется в одной области видимости IIFE, а в
returnвозвращаются ссылки только на публичные функции.
Зачем нужно
Паттерн решает проблему классического Module Pattern, где публичные и приватные функции вперемешку. В Revealing Module все функции объявляются одинаково, а публичный API явно декларируется в одном месте — в return. Это упрощает чтение кода и понимание контракта модуля.
Где используется
- Библиотеки и утилиты без ES-модулей
- Legacy-код на jQuery и ванильном JS
- Изоляция кода в браузерных расширениях
- Паттерн всё ещё применяется в обучении и понимании замыканий
Основной контент
Базовый Revealing Module
const Counter = (function {
// Все переменные и функции — приватные по умолчанию
let count = 0;
const step = 1;
function increment() {
count += step;
}
function decrement() {
if (count > 0) count -= step;
}
function reset() {
count = 0;
}
function getCount() {
return count;
}
// Явно раскрываем только публичный API
return {
increment,
decrement,
reset,
get: getCount // переименование при раскрытии
};
});
Counter.increment;
Counter.increment;
Counter.increment;
console.log(Counter.get); // 3
Counter.decrement;
console.log(Counter.get); // 2
// count и step недоступны извне
console.log(Counter.count); // undefined
Сравнение с обычным Module Pattern
// Обычный Module Pattern — публичные методы определяются в return
const ModuleA = (function {
let _private = 0;
return {
// Публичный метод определён прямо здесь
increment { _private++; },
get { return _private; }
};
});
// Revealing Module — все методы определены вверху
const ModuleB = (function {
let _private = 0;
// Всё определено одинаково
function increment() { _private++; }
function get() { return _private; }
function _helperPrivate() { /* ... */ }
// Только здесь видно что публично
return { increment, get };
});
Revealing Module с фабрикой (несколько экземпляров)
function createShoppingCart() {
const items = ;
function add(item) {
const existing = items.find(i => i.id === item.id);
if (existing) {
existing.qty++;
} else {
items.push({ ...item, qty: 1 });
}
}
function remove(id) {
const index = items.findIndex(i => i.id === id);
if (index !== -1) items.splice(index, 1);
}
function total() {
return items.reduce((sum, i) => sum + i.price * i.qty, 0);
}
function getItems() {
return [...items]; // возвращаем копию
}
function clear() {
items.length = 0;
}
return { add, remove, total, getItems, clear };
}
const cart1 = createShoppingCart;
const cart2 = createShoppingCart; // независимый экземпляр
cart1.add({ id: 1, name: 'Книга', price: 500 });
console.log(cart1.total); // 500
console.log(cart2.total); // 0
Частые ошибки
- Переопределение публичных свойств через возвращённый объект — если
Counter.increment = something, внутренняя ссылка не меняется. Другие методы модуля всё равно вызовут оригинальную функцию, что вводит в заблуждение. - Применение в проектах с ES-модулями — в современных проектах с bundler используйте нативные
export/import. Revealing Module — решение для окружений без систем модулей. - Нет поддержки наследования — паттерн не предназначен для иерархий. Для OOP используйте классы.