JavaScript Design Patterns

Introduction

Design patterns are reusable solutions to common programming problems. They help structure your code, reduce bugs, improve readability, and scale apps better. Here are the most important patterns used in modern JavaScript.

1. Singleton Pattern

Ensures only one instance of an object exists.

class Settings {
  constructor() {
    if (Settings.instance) return Settings.instance;
    this.theme = "dark";
    Settings.instance = this;
  }
}

const s1 = new Settings();
const s2 = new Settings();

console.log(s1 === s2); // true
    

2. Factory Pattern

Creates objects without specifying exact class.

function createCar(type) {
  if (type === "subaru") return { brand:"Subaru", hp:125 };
  if (type === "audi") return { brand:"Audi", hp:550 };
}

console.log(createCar("subaru"));
    

3. Module Pattern

Encapsulates private data.

const Counter = (function(){
  let count = 0;
  return {
    inc(){ count++; },
    get(){ return count; }
  };
})();

Counter.inc();
console.log(Counter.get());
    

4. Observer Pattern

Listeners react to state changes.

class EventBus {
  constructor(){ this.listeners = {}; }

  on(event, fn){
    (this.listeners[event] = this.listeners[event] || []).push(fn);
  }

  emit(event, data){
    (this.listeners[event] || []).forEach(fn => fn(data));
  }
}

const bus = new EventBus();

bus.on("login", user => console.log("User:", user));
bus.emit("login", "Kaloyan");
    

5. Strategy Pattern

Select algorithm at runtime.

const strategies = {
  add:(a,b)=>a+b,
  sub:(a,b)=>a-b
};

function calc(strategy, a, b){
  return strategies[strategy](a,b);
}

console.log(calc("add", 5, 3));
    

6. Decorator Pattern

Enhance functions dynamically.

function log(fn){
  return function(...args){
    console.log("Called with", args);
    return fn(...args);
  }
}

function sum(a,b){ return a+b; }

const logged = log(sum);
logged(3,4);
    

7. Proxy Pattern

Intercept and control access to an object.

const user = { name:"Kaloyan", age:12 };

const proxy = new Proxy(user, {
  get(target, prop){
    console.log("Accessing:", prop);
    return target[prop];
  }
});

console.log(proxy.name);
    

8. Command Pattern

Encapsulate actions as objects.

class Command {
  constructor(exec){ this.exec = exec; }
}

const helloCmd = new Command(() => console.log("Hello"));
helloCmd.exec();
    

9. MVC Pattern (Simple)

// Model
const model = { counter:0 };

// View
function render(){
  document.body.innerHTML = "Count: " + model.counter;
}

// Controller
function inc(){
  model.counter++;
  render();
}

render();
    

10. Summary