Design Patterns in JavaScript — Practical Examples

Learn essential design patterns: Singleton, Factory, Observer, Module, Strategy, and Proxy with real JavaScript examples.

General Advanced 📖 12 min

Singleton

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

Factory Pattern

function createUser(type) {
  const users = {
    admin: { role: 'admin', permissions: ['read', 'write', 'delete'] },
    editor: { role: 'editor', permissions: ['read', 'write'] },
    viewer: { role: 'viewer', permissions: ['read'] }
  };
  return { ...users[type], createdAt: new Date() };
}

const admin = createUser('admin');

Observer Pattern

class EventEmitter {
  constructor() { this.events = {}; }
  
  on(event, callback) {
    if (!this.events[event]) this.events[event] = [];
    this.events[event].push(callback);
    return () => this.off(event, callback); // unsubscribe
  }
  
  off(event, callback) {
    this.events[event] = this.events[event]?.filter(cb => cb !== callback);
  }
  
  emit(event, ...args) {
    this.events[event]?.forEach(cb => cb(...args));
  }
}

const emitter = new EventEmitter();
const unsub = emitter.on('data', (msg) => console.log(msg));
emitter.emit('data', 'Hello!'); // logs "Hello!"
unsub(); // unsubscribe

Strategy Pattern

const strategies = {
  paypal: (amount) => amount * 0.98,  // 2% fee
  stripe: (amount) => amount * 0.97,  // 3% fee
  crypto: (amount) => amount * 0.995  // 0.5% fee
};

function pay(method, amount) {
  const afterFees = strategies[method](amount);
  console.log(`Paying ${afterFees} via ${method}`);
}

Proxy Pattern

const handler = {
  get(target, prop) {
    console.log(`Accessing ${prop}`);
    return Reflect.get(target, prop);
  },
  set(target, prop, value) {
    if (prop === 'age' && (value < 0 || value > 150)) {
      throw new RangeError('Invalid age');
    }
    return Reflect.set(target, prop, value);
  }
};

const person = new Proxy({ name: 'Alice', age: 25 }, handler);

Ready to Level Up Your Coding Skills?

Join Coderz Club and learn to code with challenges, battles, and an AI mentor.

Join Coderz Club Free →