Docs LogoDocs

Common JavaScript Patterns - Ready-to-Use Code

Documentation for Common JavaScript Patterns - Ready-to-Use Code.

Common JavaScript Patterns - Ready-to-Use Code

Array Patterns

Remove Duplicates

// Using Set
const unique = [...new Set(array)];

// Using filter
const unique = array.filter((item, index) => array.indexOf(item) === index);

Flatten Array

// Shallow flatten
const flattened = array.flat();

// Deep flatten
const flattened = array.flat(Infinity);

// Manual deep flatten
function flatten(arr) {
  return arr.reduce(
    (acc, item) =>
      Array.isArray(item) ? [...acc, ...flatten(item)] : [...acc, item],
    [],
  );
}

Group By Property

const groupBy = (array, key) => {
  return array.reduce((result, item) => {
    const group = item[key];
    result[group] = result[group] || [];
    result[group].push(item);
    return result;
  }, {});
};

// Usage
const users = [
  { name: "John", role: "admin" },
  { name: "Jane", role: "user" },
  { name: "Bob", role: "admin" },
];
const grouped = groupBy(users, "role");
// { admin: [...], user: [...] }

Chunk Array

const chunk = (array, size) => {
  return array.reduce((chunks, item, index) => {
    const chunkIndex = Math.floor(index / size);
    chunks[chunkIndex] = chunks[chunkIndex] || [];
    chunks[chunkIndex].push(item);
    return chunks;
  }, []);
};

// Usage
chunk([1, 2, 3, 4, 5, 6], 2); // [[1, 2], [3, 4], [5, 6]]

Shuffle Array

const shuffle = (array) => {
  const shuffled = [...array];
  for (let i = shuffled.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
  }
  return shuffled;
};

Object Patterns

Deep Clone

// Simple objects (no functions, dates, etc.)
const clone = JSON.parse(JSON.stringify(obj));

// With structuredClone (modern browsers)
const clone = structuredClone(obj);

// Manual deep clone
function deepClone(obj) {
  if (obj === null || typeof obj !== "object") return obj;
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof Array) return obj.map((item) => deepClone(item));

  const cloned = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      cloned[key] = deepClone(obj[key]);
    }
  }
  return cloned;
}

Pick Properties

const pick = (obj, keys) => {
  return keys.reduce((result, key) => {
    if (obj.hasOwnProperty(key)) {
      result[key] = obj[key];
    }
    return result;
  }, {});
};

// Usage
const user = { name: "John", age: 30, email: "john@example.com" };
const picked = pick(user, ["name", "email"]);
// { name: 'John', email: 'john@example.com' }

Omit Properties

const omit = (obj, keys) => {
  const result = { ...obj };
  keys.forEach((key) => delete result[key]);
  return result;
};

// Usage
const user = { name: "John", password: "secret", email: "john@example.com" };
const safe = omit(user, ["password"]);
// { name: 'John', email: 'john@example.com' }

Merge Deep

function mergeDeep(target, source) {
  const output = { ...target };

  if (isObject(target) && isObject(source)) {
    Object.keys(source).forEach((key) => {
      if (isObject(source[key])) {
        if (!(key in target)) {
          output[key] = source[key];
        } else {
          output[key] = mergeDeep(target[key], source[key]);
        }
      } else {
        output[key] = source[key];
      }
    });
  }

  return output;
}

function isObject(item) {
  return item && typeof item === "object" && !Array.isArray(item);
}

Function Patterns

Debounce

function debounce(func, delay) {
  let timeoutId;
  return function (...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
}

// Usage
const searchInput = document.querySelector("#search");
searchInput.addEventListener(
  "input",
  debounce((e) => {
    console.log("Searching for:", e.target.value);
  }, 300),
);

Throttle

function throttle(func, limit) {
  let inThrottle;
  return function (...args) {
    if (!inThrottle) {
      func.apply(this, args);
      inThrottle = true;
      setTimeout(() => (inThrottle = false), limit);
    }
  };
}

// Usage
window.addEventListener(
  "scroll",
  throttle(() => {
    console.log("Scrolled!");
  }, 100),
);

Memoize

function memoize(func) {
  const cache = new Map();
  return function (...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) {
      return cache.get(key);
    }
    const result = func.apply(this, args);
    cache.set(key, result);
    return result;
  };
}

// Usage
const fibonacci = memoize((n) => {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
});

Curry

function curry(func) {
  return function curried(...args) {
    if (args.length >= func.length) {
      return func.apply(this, args);
    }
    return function (...nextArgs) {
      return curried.apply(this, [...args, ...nextArgs]);
    };
  };
}

// Usage
const add = (a, b, c) => a + b + c;
const curriedAdd = curry(add);
curriedAdd(1)(2)(3); // 6
curriedAdd(1, 2)(3); // 6

Pipe & Compose

// Pipe - left to right
const pipe =
  (...fns) =>
  (x) =>
    fns.reduce((v, f) => f(v), x);

// Compose - right to left
const compose =
  (...fns) =>
  (x) =>
    fns.reduceRight((v, f) => f(v), x);

// Usage
const double = (x) => x * 2;
const increment = (x) => x + 1;
const square = (x) => x * x;

const compute = pipe(double, increment, square);
compute(3); // ((3 * 2) + 1)² = 49

Async Patterns

Retry with Exponential Backoff

async function retry(fn, maxAttempts = 3, delay = 1000) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (error) {
      if (attempt === maxAttempts) throw error;
      await new Promise((resolve) =>
        setTimeout(resolve, delay * Math.pow(2, attempt - 1)),
      );
    }
  }
}

// Usage
const data = await retry(() => fetch("/api/data"), 3, 1000);

Timeout Promise

function timeout(promise, ms) {
  return Promise.race([
    promise,
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error("Timeout")), ms),
    ),
  ]);
}

// Usage
const data = await timeout(fetch("/api/data"), 5000);

Sequential Async Operations

async function sequential(tasks) {
  const results = [];
  for (const task of tasks) {
    results.push(await task());
  }
  return results;
}

// Usage
const tasks = [
  () => fetch("/api/users"),
  () => fetch("/api/posts"),
  () => fetch("/api/comments"),
];
const results = await sequential(tasks);

Parallel with Limit

async function parallelLimit(tasks, limit) {
  const results = [];
  const executing = [];

  for (const task of tasks) {
    const p = Promise.resolve().then(() => task());
    results.push(p);

    if (limit <= tasks.length) {
      const e = p.then(() => executing.splice(executing.indexOf(e), 1));
      executing.push(e);
      if (executing.length >= limit) {
        await Promise.race(executing);
      }
    }
  }

  return Promise.all(results);
}

DOM Patterns

Create Element with Attributes

function createElement(tag, attributes = {}, children = []) {
  const element = document.createElement(tag);

  Object.entries(attributes).forEach(([key, value]) => {
    if (key === "className") {
      element.className = value;
    } else if (key === "style" && typeof value === "object") {
      Object.assign(element.style, value);
    } else {
      element.setAttribute(key, value);
    }
  });

  children.forEach((child) => {
    if (typeof child === "string") {
      element.appendChild(document.createTextNode(child));
    } else {
      element.appendChild(child);
    }
  });

  return element;
}

// Usage
const div = createElement("div", { className: "container", id: "main" }, [
  "Hello ",
  createElement("strong", {}, ["World"]),
]);

Delegate Event

function delegate(parent, selector, event, handler) {
  parent.addEventListener(event, (e) => {
    if (e.target.matches(selector)) {
      handler.call(e.target, e);
    }
  });
}

// Usage
delegate(document.body, ".button", "click", function (e) {
  console.log("Button clicked:", this);
});

Observe Element

function observeElement(element, callback, options = {}) {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        callback(entry);
      }
    });
  }, options);

  observer.observe(element);
  return observer;
}

// Usage - Lazy load images
document.querySelectorAll("img[data-src]").forEach((img) => {
  observeElement(img, (entry) => {
    const img = entry.target;
    img.src = img.dataset.src;
    img.removeAttribute("data-src");
  });
});

Validation Patterns

Email Validation

function isValidEmail(email) {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return regex.test(email);
}

Password Strength

function checkPasswordStrength(password) {
  const checks = {
    length: password.length >= 8,
    uppercase: /[A-Z]/.test(password),
    lowercase: /[a-z]/.test(password),
    number: /\d/.test(password),
    special: /[!@#$%^&*]/.test(password),
  };

  const score = Object.values(checks).filter(Boolean).length;

  return {
    score,
    strength: score < 3 ? "weak" : score < 5 ? "medium" : "strong",
    checks,
  };
}

Form Validation

function validateForm(form, rules) {
  const errors = {};

  Object.entries(rules).forEach(([field, validators]) => {
    const value = form[field]?.value;

    validators.forEach((validator) => {
      const error = validator(value);
      if (error) {
        errors[field] = errors[field] || [];
        errors[field].push(error);
      }
    });
  });

  return {
    isValid: Object.keys(errors).length === 0,
    errors,
  };
}

// Usage
const rules = {
  email: [
    (value) => !value && "Email is required",
    (value) => !isValidEmail(value) && "Invalid email",
  ],
  password: [
    (value) => !value && "Password is required",
    (value) => value.length < 8 && "Password too short",
  ],
};

const result = validateForm(form, rules);

Storage Patterns

Local Storage with Expiry

const storage = {
  set(key, value, ttl) {
    const item = {
      value,
      expiry: ttl ? Date.now() + ttl : null,
    };
    localStorage.setItem(key, JSON.stringify(item));
  },

  get(key) {
    const itemStr = localStorage.getItem(key);
    if (!itemStr) return null;

    const item = JSON.parse(itemStr);

    if (item.expiry && Date.now() > item.expiry) {
      localStorage.removeItem(key);
      return null;
    }

    return item.value;
  },

  remove(key) {
    localStorage.removeItem(key);
  },
};

// Usage
storage.set("token", "abc123", 3600000); // 1 hour
const token = storage.get("token");

Cache with LRU

class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.cache = new Map();
  }

  get(key) {
    if (!this.cache.has(key)) return null;

    const value = this.cache.get(key);
    this.cache.delete(key);
    this.cache.set(key, value);
    return value;
  }

  set(key, value) {
    if (this.cache.has(key)) {
      this.cache.delete(key);
    } else if (this.cache.size >= this.capacity) {
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }
    this.cache.set(key, value);
  }
}

Design Patterns

Singleton

class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    Singleton.instance = this;
  }
}

// Or with closure
const Singleton = (function () {
  let instance;

  return class {
    constructor() {
      if (instance) return instance;
      instance = this;
    }
  };
})();

Observer (PubSub)

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

  on(event, callback) {
    this.events[event] = this.events[event] || [];
    this.events[event].push(callback);
  }

  off(event, callback) {
    if (!this.events[event]) return;
    this.events[event] = this.events[event].filter((cb) => cb !== callback);
  }

  emit(event, data) {
    if (!this.events[event]) return;
    this.events[event].forEach((callback) => callback(data));
  }

  once(event, callback) {
    const wrapper = (data) => {
      callback(data);
      this.off(event, wrapper);
    };
    this.on(event, wrapper);
  }
}

Factory

class UserFactory {
  static create(type, data) {
    switch (type) {
      case "admin":
        return new Admin(data);
      case "moderator":
        return new Moderator(data);
      default:
        return new User(data);
    }
  }
}

Module Pattern

const Module = (function () {
  // Private
  let privateVar = "private";

  function privateMethod() {
    console.log(privateVar);
  }

  // Public API
  return {
    publicMethod() {
      privateMethod();
    },

    get value() {
      return privateVar;
    },
  };
})();
Last updated on July 15, 2026

On this page