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); // 6Pipe & 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)² = 49Async 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