Design Patterns in JavaScript with Examples: From A to Z

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Design Patterns in JavaScript with Examples: From A to Z



Design patterns are proven solutions to common problems that arise during software development. In JavaScript, especially in the Node.js environment, understanding these patterns helps write cleaner, more modular, and scalable code. In this article, we will break down the main categories of patterns with clear examples.



1. Creational Patterns

These patterns manage the object creation process, making the system independent of how objects are instantiated.



1.1. Singleton

Ensures a class has only one instance and provides a global point of access to it. In Node.js, modules are cached by default, which simplifies the implementation.

class DatabaseConnection {  constructor() {    if (DatabaseConnection.instance) {      return DatabaseConnection.instance;    }    this.connection = null;    DatabaseConnection.instance = this;  }

connect() { if (!this.connection) { this.connection = { status: 'connected' }; console.log('New DB connection'); } return this.connection; }}

const db1 = new DatabaseConnection();const db2 = new DatabaseConnection();console.log(db1 === db2); // true


1.2. Factory Method

Defines an interface for creating an object but lets subclasses alter the type of created object. It is ideal for creating different types of loggers.

class LoggerFactory {  createLogger(type) {    switch (type) {      case 'console':        return new ConsoleLogger();      case 'file':        return new FileLogger();      default:        throw new Error('Unknown logger type');    }  }}

class ConsoleLogger { log(message) { console.log(message); }}

class FileLogger { log(message) { console.log(`[File]: ${message}`); }}

const factory = new LoggerFactory();const logger = factory.createLogger('console');logger.log('Test message');


2. Structural Patterns

Describe ways to combine classes and objects to form larger structures.



2.1. Decorator

Dynamically adds new responsibilities to an object. In JavaScript, decorators are often implemented via higher-order functions or prototypes.

class Coffee {  cost() { return 10; }  description() { return 'Coffee'; }}

function withMilk(coffee) { coffee.cost = () => coffee.cost() + 5; coffee.description = () => coffee.description() + ', with milk'; return coffee;}

function withSugar(coffee) { coffee.cost = () => coffee.cost() + 2; coffee.description = () => coffee.description() + ', with sugar'; return coffee;}

let myCoffee = new Coffee();myCoffee = withMilk(myCoffee);myCoffee = withSugar(myCoffee);console.log(`${myCoffee.description()}: ${myCoffee.cost()} rub.`); // Coffee, with milk, with sugar: 17 rub.


2.2. Adapter

Converts the interface of one class into another interface expected by the client. It is especially useful when integrating third-party libraries.

class OldAPI {  getUserData() {    return { name: 'Ivan', age: 25, email: 'ivan@example.com' };  }}

class NewAPI { fetchUser() { return { fullName: 'Ivan Petrov', yearsOld: 26, contact: 'ivan@example.com' }; }}

class UserAdapter { constructor(api) { this.api = api; }

getUserData() { const data = this.api.fetchUser(); return { name: data.fullName, age: data.yearsOld, email: data.contact }; }}

const adapter = new UserAdapter(new NewAPI());console.log(adapter.getUserData()); // { name: 'Ivan Petrov', age: 26, email: 'ivan@example.com' }


3. Behavioral Patterns

Define algorithms

Blogs

Book Recommendations