Module Pattern
Encapsulate code using closures to create private scope
Pattern Overview
📦 Module Pattern
The Module Pattern uses closures to create encapsulated modules with private variables and methods, exposing only a public API. It's fundamental to JavaScript's module system and provides namespace management.
Core Concepts
🔹 IIFE (Immediately Invoked Function Expression) - Creates private scope
🔹 Closures - Enable access to private variables from public methods
🔹 Public API - Object returned with methods/properties to expose
🔹 Private State - Variables and functions accessible only within module
Real-World Applications
Library Development - jQuery, Lodash use module patterns for encapsulation Application State - Manage app state without global variables Utility Functions - Group related functionality with shared private state Configuration Management - Encapsulate settings with controlled accessEncapsulation Benefits
Private Variables - Cannot be accessed from outside the module Namespace Management - Prevents global scope pollution API Control - Only expose what users should access State Protection - Internal state cannot be corrupted externallyModern Alternatives
ES6 Modules - Native import/export system TypeScript Namespaces - Compile-time module organization Class-based Encapsulation - Private fields and methods Module Bundlers - Webpack, Rollup provide module isolationImplementation Benefits
✅ True privacy - Private variables cannot be accessed externally
✅ Controlled API - Expose only intended functionality
✅ Namespace isolation - Prevent naming collisions
✅ Singleton behavior - Single instance with shared state
Examples:
const counter = createCounterInstance();
console.log('Initial:', counter.getCurrentValue());
counter.increment();
counter.increment();
console.log('After increments:', counter.getCurrentValue());
// Try to access private variables (this won't work)
console.log('Private count:', (counter as any).count); // undefined
console.log('History:', counter.getHistory());Initial: 0
[Counter] increment: 1
[Counter] increment: 2
After increments: 2
Private count: undefined
History: [1, 2]const cart = createShoppingCart();
cart.addItem({ id: '1', name: 'Laptop', price: 999, quantity: 1 });
cart.addItem({ id: '2', name: 'Mouse', price: 25, quantity: 2 });
console.log('Items:', cart.getItemCount());
console.log('Total quantity:', cart.getTotalQuantity());
console.log('Total price: $' + cart.getTotal());
cart.setDiscountRate(0.1);
console.log('With 10% discount: $' + cart.getTotal());Items: 2
Total quantity: 3
Total price: $1049
With 10% discount: $944.1const auth = createAuthSystem();
console.log('Initially authenticated:', auth.isAuthenticated());
const loginResult = auth.login('admin', 'admin123');
console.log('Login result:', loginResult.success);
console.log('Current user:', auth.getCurrentUser()?.username);
console.log('Has admin role:', auth.hasRole('admin'));
auth.logout();
console.log('After logout:', auth.isAuthenticated());Initially authenticated: false
Login result: true
Current user: admin
Has admin role: true
After logout: falseConcepts
Complexity Analysis
Implementation
counter-module
// Classic Module Pattern using IIFE
const CounterModule = (function() {
// Private variables
let count = 0;
let history: number[] = [];
// Private functions
function log(action: string, value: number) {
console.log(`[Counter] ${action}: ${value}`);
}
// Public API
return {
increment(): number {
count++;
history.push(count);
log('increment', count);
return count;
},
decrement(): number {
count--;
history.push(count);
log('decrement', count);
return count;
},
getCurrentValue(): number {
return count;
},
getHistory(): readonly number[] {
return [...history]; // Return copy to prevent external modification
},
reset(): void {
count = 0;
history = [];
log('reset', count);
}
};
})();
// Factory function to create new instances
function createCounterInstance() {
return CounterModule;
}