Module Pattern
The module pattern uses closures to create private state and expose a public API. It's one of the most widely used JavaScript patterns for organizing code.
const Counter = (() => {
let count = 0; // Private
return {
increment() { count++; },
decrement() { count--; },
getCount() { return count; },
};
})();
Counter.increment();
Counter.increment();
console.log(Counter.getCount()); // 2
console.log(count); // ❌ Not accessible
Observer Pattern
The observer pattern lets objects subscribe to and receive notifications from other objects. It's the basis of event systems and reactive programming.
class EventEmitter {
constructor() {
this.listeners = {};
}
on(event, callback) {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event].push(callback);
}
emit(event, ...args) {
if (this.listeners[event]) {
this.listeners[event].forEach(cb => cb(...args));
}
}
}
const emitter = new EventEmitter();
emitter.on("data", (msg) => console.log("Received:", msg));
emitter.emit("data", "Hello!");
Singleton Pattern
The singleton ensures a class has only one instance and provides a global point of access to it. It's useful for shared resources like database connections or configuration.
class Database {
static #instance = null;
static getInstance() {
if (!Database.#instance) {
Database.#instance = new Database();
}
return Database.#instance;
}
connect() {
console.log("Connected to database");
}
}
const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2); // true — same instance
Try it Yourself →
Factory Pattern
Factories create objects without using the new keyword. They're flexible — you can return different types of objects based on input.
function createUser(type) {
const base = {
name: "",
login() { console.log(`${this.name} logged in`); },
};
switch (type) {
case "admin":
return { ...base, role: "admin", delete() {} };
case "guest":
return { ...base, role: "guest", browse() {} };
default:
return { ...base, role: "user" };
}
}
const admin = createUser("admin");
admin.login(); // " logged in"
Summary
Design patterns are reusable solutions to common problems. The module, observer, singleton, and factory patterns are essential tools in every JavaScript developer's toolkit.