Design Patterns in JavaScript

10 questions found

What is the Module pattern and what problem does it solve?

Beginner
The Module pattern uses a function closure (or an ES module) to keep internal variables private and expose only a controlled public API, preventing external code from directly manipulating internal state.
const counter = (function () {
  let count = 0;
  return {
    increment: () => ++count,
    get: () => count
  };
})();
counter.increment();
console.log(counter.get()); // 1
Real-world example Building a small state-tracking utility without leaking its internal variable to the global scope.

Common follow-ups: How do native ES modules make the classic IIFE module pattern less necessary today?

Scope Hoisting & Closures

What is the Singleton pattern and how is it implemented in JavaScript?

Beginner
Singleton ensures only one instance of an object exists across the whole application, typically by exporting a single already-created instance from a module — since ES modules are cached, importing it anywhere returns the same instance.
// config.js
class Config {
  constructor() { this.settings = {}; }
}
export default new Config(); // same instance everywhere it's imported
Real-world example A single shared application configuration or logger instance used across many files.

Common follow-ups: What are the downsides of overusing Singletons, especially for testing?

ES Modules

How do you implement the Observer pattern in JavaScript?

Intermediate
Maintain a list of subscriber callback functions; provide a subscribe() method to add them and a notify() (or emit()) method that loops through and calls each one when an event occurs — this decouples the event source from its consumers.
class EventEmitter {
  #listeners = [];
  subscribe(fn) { this.#listeners.push(fn); }
  emit(data) { this.#listeners.forEach(fn => fn(data)); }
}
Real-world example Powering a custom pub-sub system for decoupled communication between UI components.

Common follow-ups: How does Node's built-in EventEmitter class relate to this pattern?

Classes & Class Syntax

What is the Factory pattern, and how does it differ from calling a class constructor directly?

Intermediate
A factory is a function that encapsulates the logic for deciding which class/object to instantiate and how, hiding that complexity from the caller — useful when construction logic is conditional or needs to vary at runtime.
function createShape(type) {
  switch (type) {
    case 'circle': return new Circle();
    case 'square': return new Square();
    default: throw new Error('Unknown shape');
  }
}
Real-world example A UI library's createElement() function that returns different component instances based on a type string.

Common follow-ups: When would you prefer a factory function over exposing the classes directly?

Classes & Class Syntax

How is the Decorator pattern typically implemented in JavaScript?

Intermediate
By wrapping a function or object with another function that adds behavior before/after calling the original, while preserving its original interface — often done with higher-order functions rather than the class decorator proposal.
function withLogging(fn) {
  return (...args) => {
    console.log('calling with', args);
    return fn(...args);
  };
}
const loggedAdd = withLogging((a, b) => a + b);
Real-world example Wrapping an API call function to automatically add logging or retry behavior without modifying the original function.

Common follow-ups: How does this differ from the experimental @decorator class syntax?

Functional Programming

What is the Strategy pattern and how does it help avoid large if/else chains?

Advanced
Strategy defines a family of interchangeable algorithms/behaviors as separate functions or objects, and lets you swap which one is used at runtime, replacing sprawling conditional logic with a simple lookup or injected dependency.
const strategies = {
  card: (amt) => payWithCard(amt),
  paypal: (amt) => payWithPaypal(amt),
};
function pay(method, amount) {
  return strategies[method](amount);
}
Real-world example Supporting multiple payment or shipping calculation methods that can be swapped without touching the core checkout logic.

Common follow-ups: How does Strategy relate to dependency injection?

Design Patterns in JavaScript

How do you implement the Proxy pattern using JavaScript's built-in Proxy object?

Advanced
JavaScript's native Proxy wraps a target object with traps (get, set, has, etc.) that intercept and can customize fundamental operations on it, letting you add validation, logging, or virtual properties transparently.
const validated = new Proxy({}, {
  set(target, prop, value) {
    if (prop === 'age' && value < 0) throw new Error('Invalid age');
    target[prop] = value;
    return true;
  }
});
validated.age = -5; // throws
Real-world example Building a reactive state object (like Vue 3's reactivity system) that tracks property reads and writes.

Common follow-ups: What performance cost does wrapping objects in Proxy typically add?

Proxy & Reflect

What is the Command pattern and where is it useful in JavaScript apps?

Advanced
Command encapsulates an action (and its parameters) as an object with a consistent execute() method, so actions can be queued, logged, undone, or passed around independently of the code that triggers them.
class AddItemCommand {
  constructor(cart, item) { this.cart = cart; this.item = item; }
  execute() { this.cart.push(this.item); }
  undo() { this.cart.pop(); }
}
Real-world example Implementing undo/redo functionality in a drawing or text-editing application.

Common follow-ups: How does Command relate to Redux-style actions and reducers?

Functional Programming

What is the Adapter pattern and why is it useful when integrating third-party code?

Advanced
Adapter wraps an incompatible interface with a new one that matches what your code expects, letting you swap or update the underlying library without rewriting all the code that depends on it.
class LegacyLogger {
  logMessage(msg) { console.log('LEGACY:', msg); }
}
class LoggerAdapter {
  #legacy = new LegacyLogger();
  log(msg) { this.#legacy.logMessage(msg); } // matches modern interface
}
Real-world example Wrapping an old third-party analytics SDK so the rest of the app can call a consistent, modern log() API.

Common follow-ups: How does Adapter differ from Facade, which also 'wraps' something?

Classes & Class Syntax

When is it a mistake to force a 'classic' design pattern into idiomatic JavaScript?

Advanced
Many GoF patterns exist to work around limitations of statically-typed, class-heavy languages. JavaScript's first-class functions and closures often solve the same problem more simply — e.g., a full class-based Strategy pattern is often overkill when a plain object of functions or even a single higher-order function would do.
// Overkill class-based Strategy:
class AddStrategy { execute(a,b) { return a+b; } }

// Idiomatic JS equivalent:
const add = (a, b) => a + b;
Real-world example Recognizing when a Java-style pattern is being copy-pasted into JS unnecessarily, adding ceremony without benefit.

Common follow-ups: What JavaScript language features most commonly replace the need for classic OOP patterns?

Functional Programming