DEV Community

SOVANNARO
SOVANNARO

Posted on

10 JavaScript Design Patterns Every Developer Should Know

Hey there, fellow developer! ๐Ÿ‘‹ Have you ever felt like your JavaScript code could be cleaner, more organized, or just easier to manage? Well, you're not alone! Writing maintainable and scalable JavaScript is an art, and design patterns are here to help. Today, letโ€™s explore 10 essential JavaScript design patterns that will not only level up your coding skills but also make your codebase a joy to work with. Grab a coffee โ˜• and letโ€™s dive in!


1. Singleton Pattern โ˜๏ธ

Imagine you have a coffee machine in your office, and everyone shares it. You donโ€™t want multiple instances of the machine popping upโ€”just one for everyone. Thatโ€™s exactly what the Singleton pattern does in JavaScript. It ensures that a class has only one instance and provides a global point of access to it.

class Singleton {
  constructor() {
    if (!Singleton.instance) {
      Singleton.instance = this;
    }
    return Singleton.instance;
  }
}
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // true
Enter fullscreen mode Exit fullscreen mode

2. Factory Pattern ๐Ÿญ

Ever ordered a coffee at a cafรฉ? You tell them what you want, and they prepare it without you worrying about the details. The Factory pattern follows this idea by creating objects without specifying the exact class of the object being created.

class CoffeeFactory {
  static createCoffee(type) {
    if (type === "Espresso") return new Espresso();
    if (type === "Latte") return new Latte();
    throw new Error("Unknown coffee type");
  }
}
const myCoffee = CoffeeFactory.createCoffee("Espresso");
Enter fullscreen mode Exit fullscreen mode

3. Observer Pattern ๐Ÿ‘€

Ever signed up for YouTube notifications? When a new video is uploaded, all subscribers get notified. The Observer pattern allows objects (subscribers) to react to changes in another object (publisher).

class Subject {
  constructor() { this.observers = []; }
  subscribe(observer) { this.observers.push(observer); }
  unsubscribe(observer) { this.observers = this.observers.filter(o => o !== observer); }
  notify(data) { this.observers.forEach(observer => observer.update(data)); }
}
Enter fullscreen mode Exit fullscreen mode

4. Module Pattern ๐Ÿ“ฆ

Do you love keeping your workspace tidy? The Module pattern helps keep your code organized by encapsulating functionality into reusable modules.

const Calculator = (function () {
  let result = 0;
  return {
    add: (num) => (result += num),
    getResult: () => result,
  };
})();
Calculator.add(5);
console.log(Calculator.getResult()); // 5
Enter fullscreen mode Exit fullscreen mode

5. Prototype Pattern ๐Ÿงฌ

Ever copied and modified an existing document? The Prototype pattern lets you create objects based on an existing one.

const car = { wheels: 4, drive: () => console.log("Vroom!") };
const myCar = Object.create(car);
console.log(myCar.wheels); // 4
Enter fullscreen mode Exit fullscreen mode

6. Decorator Pattern ๐ŸŽจ

Imagine ordering a coffee and adding extra toppings like caramel or whipped cream. The Decorator pattern allows you to enhance the behavior of objects dynamically.

function Coffee() { this.cost = () => 5; }
function MilkDecorator(coffee) {
  const cost = coffee.cost();
  coffee.cost = () => cost + 2;
}
const myCoffee = new Coffee();
MilkDecorator(myCoffee);
console.log(myCoffee.cost()); // 7
Enter fullscreen mode Exit fullscreen mode

7. Command Pattern ๐ŸŽฎ

Like a remote control, the Command pattern encapsulates requests as objects, allowing users to execute, undo, or queue them.

class Command {
  constructor(execute, undo) {
    this.execute = execute;
    this.undo = undo;
  }
}
const turnOn = new Command(() => console.log("Light On"), () => console.log("Light Off"));
turnOn.execute(); // Light On
turnOn.undo(); // Light Off
Enter fullscreen mode Exit fullscreen mode

8. Strategy Pattern ๐Ÿง 

Want to switch between different ways of doing something dynamically? The Strategy pattern lets you swap out algorithms on the fly.

class PaymentStrategy {
  pay(amount) {}
}
class CreditCardPayment extends PaymentStrategy {
  pay(amount) { console.log(`Paid ${amount} with Credit Card`); }
}
class PayPalPayment extends PaymentStrategy {
  pay(amount) { console.log(`Paid ${amount} via PayPal`); }
}
const payment = new CreditCardPayment();
payment.pay(100);
Enter fullscreen mode Exit fullscreen mode

9. Proxy Pattern ๐Ÿ›ก๏ธ

Think of a proxy as a personal assistant. Instead of talking directly to a VIP, you go through their assistant. The Proxy pattern provides an object that controls access to another object.

class RealSubject {
  request() { console.log("Handling request..."); }
}
class Proxy {
  constructor(realSubject) { this.realSubject = realSubject; }
  request() {
    console.log("Checking access...");
    this.realSubject.request();
  }
}
const proxy = new Proxy(new RealSubject());
proxy.request();
Enter fullscreen mode Exit fullscreen mode

10. Mediator Pattern ๐Ÿ—ฃ๏ธ

Think of a group chat where a mediator (the chat app) manages communication between participants. The Mediator pattern helps reduce dependencies between objects.

class Mediator {
  sendMessage(user, message) { console.log(`${user} says: ${message}`); }
}
const chatMediator = new Mediator();
chatMediator.sendMessage("Alice", "Hello, world!");
Enter fullscreen mode Exit fullscreen mode

Wrapping Up ๐ŸŽ

These 10 JavaScript design patterns will help you write cleaner, more maintainable, and more efficient code. Each pattern solves a different problem, so try them out and see how they fit into your projects!

If you found this article helpful, donโ€™t forget to star my GitHub repo ๐Ÿ‘‰ GitHub and buy me a coffee โ˜• Buy Me a Coffee. Your support keeps me motivated to create more content! ๐Ÿ’–

Happy coding! ๐Ÿš€

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.