JavaScript Design Patterns

Definition

Reusable structural solutions for JavaScript applications — the classic Gang-of-Four patterns as they actually appear in JS, plus the React-specific patterns that grew from component composition. Many were superseded by Hooks, which is itself the most useful thing to know about them.


Core Ideas

Object creation and sharing

PatternPurposeTrade-off
Singletonone global instance app-widehard to unit test — state can be mutated anywhere; arguably breaks single responsibility by solving both “one instance” and “global access point”. Redux / React Context are effectively singletons
Prototypeshare properties across objects of a type via the prototype chain (Object.create)native to JS, but generally not recommended in modern code
Factorya function returning an object, no newgood for many small objects with shared shape or environment-specific construction; often just a function returning an object literal, and creating instances can be more memory-efficient
Flyweightreuse instances for identical objects (an object pool)mattered when RAM was scarce; prototypal inheritance plus GB-scale RAM makes it mostly obsolete
Mixinadd behavior without inheritance (Object.assign)modifies prototypes → prototype pollution and unclear function origins. React explicitly discourages it

Interception and communication

  • Proxy — wraps an object to control its behavior via Proxy/Reflect (a form of metaprogramming: programs treating programs as data). Useful for validation, formatting, notification, and debugging. Overuse costs performance.
  • Observer — subscribers get notified on events; strong fit for asynchronous, event-based data. Enforces separation of concerns; a too-complex observer becomes a performance problem when notifying all subscribers. RxJS is the reference implementation.
  • Mediator / Middleware — route all communication through one central point to collapse many-to-many relationships into many-to-one.
  • Command — send commands to a commander instead of calling methods directly. Earns its keep for queued or time-scheduled commands with a lifespan; otherwise it is boilerplate.

Module structure

Module pattern — split code into smaller reusable pieces. Two distinct wins: encapsulation (nothing private leaks; no name collision or global-scope pollution) and dynamic import (load, parse, and compile only what the user needs, when they need it).

React composition patterns

  • Provider — make data available to a deep tree without props drilling (e.g. an MUI theme provider).
  • Container / Presentation — container fetches data, presentation renders UI. Superseded by hooks: the hook now owns data fetching and can be called directly inside the presentational component.
  • Render props — pass JSX through props to separate logic from render. Solves the same problem as HOCs; largely replaced by hooks.
  • Higher-Order Components (HOC) — wrap a component to inject reusable logic as props. Keeps shared logic in one place (DRY, fewer duplicated bugs); risk is prop-name collision.
  • Hooks — reuse stateful logic as plain functions; state and partial lifecycle without classes.
  • Compound components — several components cooperating on one task, sharing internal state managed by the parent (Semantic UI style). Ideal for component libraries: consumers don’t import children explicitly and don’t manage the shared state.

HOC vs Hooks — the actual decision rule

Use a HOC when:

  • the same uncustomized behavior is needed by many components
  • the component works standalone without the added logic

Use Hooks when:

  • the behavior must be customized per component
  • only one or a few components need it
  • the behavior would add many props to the component

Relationships

  • React — most of the composition patterns here are React-specific, and several are now history
  • Web Rendering and Performance Patterns — the sibling half of the same reading; the module pattern’s dynamic import is where the two meet
  • TypeScript — structural typing changes how several of these patterns are expressed
  • SOLID — singleton’s single-responsibility problem and the observer’s separation of concerns are SOLID arguments
  • Software Engineering Practices

References

  • JS Pattern — 1 Design Patterns of JS and React
  • patterns.dev