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
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");
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)); }
}
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
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
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
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
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);
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();
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!");
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.