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
| Pattern | Purpose | Trade-off |
|---|---|---|
| Singleton | one global instance app-wide | hard 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 |
| Prototype | share properties across objects of a type via the prototype chain (Object.create) | native to JS, but generally not recommended in modern code |
| Factory | a function returning an object, no new | good 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 |
| Flyweight | reuse instances for identical objects (an object pool) | mattered when RAM was scarce; prototypal inheritance plus GB-scale RAM makes it mostly obsolete |
| Mixin | add 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