ReviseAlgo Logo

Design Patterns

Decorator Pattern

Master the Decorator Pattern in JavaScript. Learn to extend object behavior dynamically by wrapping objects, rather than using rigid class inheritance.

Last Updated: July 15, 2026 10 min read

1. Introduction

The Decorator Pattern is a structural design pattern that allows you to add behavior or properties to individual objects dynamically, wrapping them in a helper class or function, without modifying the underlying class blueprints.

2. Why It Matters

Using inheritance to add features to objects can result in a massive number of subclasses (e.g. creating subclasses like MilkCoffee, SugarCoffee, and MilkSugarCoffee). The Decorator pattern avoids this class explosion by allowing you to stack features dynamically at runtime.

3. Real-World Analogy

Think of Dressing up in Winter Clothes:

  • Class Inheritance (Genetic modifications): Designing a custom human subclass for every winter setting: a "HeavyCoatedHuman", a "ScarvedHuman", or a "HeavyCoatedScarvedHuman". It is rigid and cannot be changed on the fly.
  • Decorator Pattern (Stackable clothes): You have a base "Human" object. When it gets cold, you wrap the human in a "CoatDecorator". If it starts snowing, you wrap the coat in a "ScarfDecorator". You add layers (behaviors) dynamically at runtime, leaving the base human unmodified.

4. Implementing the Decorator

In classic Object-Oriented JavaScript, you implement a Decorator by creating a wrapper class that maintains a reference to the target object, forwarding operations to it while adding custom logic:

5. Functional Decorators

In JavaScript, you can write functional decorators that wrap functions directly, which is a common pattern in web development:

6. Practical Example

This script demonstrates wrapping a standard network service call in a caching decorator to store and reuse query responses:

7. Common Mistakes

  • Losing the object prototype chain when wrapping: When wrapping an object, the decorator instance is not an instance of the base class. Sibling checks like instanceof BaseClass will return false. Ensure you design decorators to handle type validation checks or implement shared interfaces.

8. Quick Quiz

Q1: What is the primary benefit of the Decorator Pattern over standard inheritance?

A) It is compiled and runs faster

B) It allows behaviors to be added or modified dynamically at runtime without causing a subclass explosion

Answer: B — The Decorator pattern allows you to stack behaviors dynamically at runtime, avoiding rigid inheritance hierarchies and class explosion.

9. Scenario-Based Challenge

The Multi-Layer Logger Formatter:

An application prints logs: { print(msg) }. You want to dynamically wrap this printer with a timestamp prefix, and then wrap it with an error tag prefix if the log is an error. Write these stackable decorators.

10. Debugging Exercise

Explain why this decorator fails to compile or run, and how to fix it:

class TextFormatter {
  render(txt) { return txt; }
}

class BoldDecorator { constructor(formatter) { this.formatter = formatter; }

// Bug: forgot to mirror the argument list in the decorator method! render() { return `<b>${this.formatter.render()}</b>`; // crashes with undefined! Why? } } const b = new BoldDecorator(new TextFormatter()); b.render('hello');

View Solution

Diagnosis: The decorator method render() does not accept the arguments passed by the caller, causing it to call the underlying formatter with no arguments (which evaluates to undefined).

Fix: Pass arguments through the decorator methods using rest parameters:

class BoldDecorator {
  constructor(formatter) {
    this.formatter = formatter;
  }

render(...args) { // Accept arguments return `<b>${this.formatter.render(...args)}</b>`; // Pass through } }

11. Interview Questions

🟢 Q1: Compare the Decorator Pattern and Class Inheritance in terms of design flexibility.

Answer:
Class Inheritance: A compile-time association. Behaviors are defined statically in subclasses, which can lead to a subclass explosion when combining multiple optional features.
Decorator Pattern: A runtime association. You stack behaviors dynamically at runtime by wrapping objects, allowing you to combine features flexibly without modifying the underlying class blueprints.

12. Production Considerations

  • Interface Matching: When implementing decorators, ensure the decorator class mirrors the base class interface exactly (all methods and properties) to prevent errors when swapping objects.