Labs ICT
Pro Login

Common Patterns

2 min read | JavaScript Tutorial

Want the full learning experience?

Get structured courses, certificates, projects, and instructor support with LabsICT Pro.

Explore Pro Courses

Module Pattern

The module pattern uses closures to create private state and expose a public API. It's one of the most widely used JavaScript patterns for organizing code.

const Counter = (() => {
  let count = 0; // Private

  return {
    increment() { count++; },
    decrement() { count--; },
    getCount() { return count; },
  };
})();

Counter.increment();
Counter.increment();
console.log(Counter.getCount()); // 2
console.log(count); // ❌ Not accessible

Observer Pattern

The observer pattern lets objects subscribe to and receive notifications from other objects. It's the basis of event systems and reactive programming.

class EventEmitter {
  constructor() {
    this.listeners = {};
  }

  on(event, callback) {
    if (!this.listeners[event]) {
      this.listeners[event] = [];
    }
    this.listeners[event].push(callback);
  }

  emit(event, ...args) {
    if (this.listeners[event]) {
      this.listeners[event].forEach(cb => cb(...args));
    }
  }
}

const emitter = new EventEmitter();
emitter.on("data", (msg) => console.log("Received:", msg));
emitter.emit("data", "Hello!");

Singleton Pattern

The singleton ensures a class has only one instance and provides a global point of access to it. It's useful for shared resources like database connections or configuration.

class Database {
  static #instance = null;

  static getInstance() {
    if (!Database.#instance) {
      Database.#instance = new Database();
    }
    return Database.#instance;
  }

  connect() {
    console.log("Connected to database");
  }
}

const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2); // true — same instance

Factory Pattern

Factories create objects without using the new keyword. They're flexible — you can return different types of objects based on input.

function createUser(type) {
  const base = {
    name: "",
    login() { console.log(`${this.name} logged in`); },
  };

  switch (type) {
    case "admin":
      return { ...base, role: "admin", delete() {} };
    case "guest":
      return { ...base, role: "guest", browse() {} };
    default:
      return { ...base, role: "user" };
  }
}

const admin = createUser("admin");
admin.login(); // " logged in"

Summary

Design patterns are reusable solutions to common problems. The module, observer, singleton, and factory patterns are essential tools in every JavaScript developer's toolkit.