Skip to content

Cookbook - Practical JavaScript Recipes

Welcome to the JavaScript Cookbook! This collection contains practical, ready-to-use code snippets and solutions for common programming challenges.

Group array elements by a specific property.

// Group objects by property
function groupBy(array, key) {
return array.reduce((groups, item) => {
const group = item[key];
groups[group] = groups[group] || [];
groups[group].push(item);
return groups;
}, {});
}
const users = [
{ name: 'Alice', department: 'Engineering' },
{ name: 'Bob', department: 'Marketing' },
{ name: 'Charlie', department: 'Engineering' }
];
const grouped = groupBy(users, 'department');
// { Engineering: [Alice, Charlie], Marketing: [Bob] }
// Modern approach with Object.groupBy() (ES2024)
const modernGrouped = Object.groupBy(users, user => user.department);

Remove duplicate values from arrays.

// Simple deduplication
const numbers = [1, 2, 2, 3, 3, 4, 5];
const unique = [...new Set(numbers)]; // [1, 2, 3, 4, 5]
// Deduplicate objects by property
function uniqueBy(array, key) {
const seen = new Set();
return array.filter(item => {
const value = item[key];
if (seen.has(value)) return false;
seen.add(value);
return true;
});
}
const products = [
{ id: 1, name: 'Phone' },
{ id: 2, name: 'Laptop' },
{ id: 1, name: 'Phone' }
];
const uniqueProducts = uniqueBy(products, 'id');
// [{ id: 1, name: 'Phone' }, { id: 2, name: 'Laptop' }]

Split arrays into smaller chunks.

function chunk(array, size) {
const chunks = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
}
const items = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const chunked = chunk(items, 3);
// [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
// Functional approach
const functionalChunk = (arr, size) =>
Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
arr.slice(i * size, i * size + size)
);

Various string manipulation utilities.

// Title case
function titleCase(str) {
return str
.toLowerCase()
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
}
// Camel case
function camelCase(str) {
return str
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) =>
index === 0 ? word.toLowerCase() : word.toUpperCase()
)
.replace(/\s+/g, '');
}
// Snake case
function snakeCase(str) {
return str
.replace(/\W+/g, ' ')
.split(/ |\B(?=[A-Z])/)
.map(word => word.toLowerCase())
.join('_');
}
// Kebab case
function kebabCase(str) {
return str
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/\s+/g, '-')
.toLowerCase();
}
console.log(titleCase('hello world')); // "Hello World"
console.log(camelCase('hello world')); // "helloWorld"
console.log(snakeCase('Hello World')); // "hello_world"
console.log(kebabCase('Hello World')); // "hello-world"

Truncate strings with ellipsis.

function truncate(str, length, ending = '...') {
if (str.length <= length) return str;
return str.slice(0, length - ending.length) + ending;
}
// Word-aware truncation
function truncateWords(str, wordLimit, ending = '...') {
const words = str.split(' ');
if (words.length <= wordLimit) return str;
return words.slice(0, wordLimit).join(' ') + ending;
}
console.log(truncate('This is a long sentence', 10));
// "This is..."
console.log(truncateWords('This is a very long sentence', 4));
// "This is a very..."

Create deep copies of objects.

// Simple deep clone (limitations with functions, dates, etc.)
function simpleDeepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
// More robust deep clone
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (obj instanceof Date) return new Date(obj.getTime());
if (obj instanceof Array) return obj.map(item => deepClone(item));
if (obj instanceof Object) {
const cloned = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}
}
// Modern approach with structuredClone (where supported)
const cloned = structuredClone(originalObject);

Merge objects with different strategies.

// Shallow merge
function shallowMerge(...objects) {
return Object.assign({}, ...objects);
}
// Deep merge
function deepMerge(target, ...sources) {
if (!sources.length) return target;
const source = sources.shift();
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) Object.assign(target, { [key]: {} });
deepMerge(target[key], source[key]);
} else {
Object.assign(target, { [key]: source[key] });
}
}
}
return deepMerge(target, ...sources);
}
function isObject(item) {
return item && typeof item === 'object' && !Array.isArray(item);
}
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { b: { d: 3 }, e: 4 };
const merged = deepMerge({}, obj1, obj2);
// { a: 1, b: { c: 2, d: 3 }, e: 4 }

Delay function execution until after a pause in calls.

function debounce(func, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
// Usage example
const searchInput = document.getElementById('search');
const debouncedSearch = debounce((query) => {
console.log('Searching for:', query);
// Perform search API call
}, 300);
searchInput.addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});

Limit function execution to at most once per specified interval.

function throttle(func, limit) {
let inThrottle;
return function (...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// Usage example
const throttledScroll = throttle(() => {
console.log('Scroll event');
}, 100);
window.addEventListener('scroll', throttledScroll);

Retry failed operations with increasing delays.

async function retryWithBackoff(fn, maxRetries = 3, baseDelay = 1000) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxRetries) throw error;
const delay = baseDelay * Math.pow(2, attempt);
console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms`);
await sleep(delay);
}
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Usage
async function fetchData() {
const response = await fetch('/api/data');
if (!response.ok) throw new Error('Network error');
return response.json();
}
retryWithBackoff(fetchData, 3, 1000)
.then(data => console.log('Success:', data))
.catch(error => console.error('Failed after retries:', error));

Useful Promise-based utilities.

// Timeout wrapper
function withTimeout(promise, ms) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms)
);
return Promise.race([promise, timeout]);
}
// Parallel execution with concurrency limit
async function pMap(array, mapper, concurrency = Infinity) {
const results = [];
const executing = [];
for (const [index, item] of array.entries()) {
const promise = Promise.resolve().then(() => mapper(item, index));
results.push(promise);
if (array.length >= concurrency) {
executing.push(promise.then(() => executing.splice(executing.indexOf(promise), 1)));
}
if (executing.length >= concurrency) {
await Promise.race(executing);
}
}
return Promise.all(results);
}
// Usage
const urls = ['url1', 'url2', 'url3', 'url4', 'url5'];
const results = await pMap(urls, async (url) => {
const response = await fetch(url);
return response.json();
}, 2); // Max 2 concurrent requests

Helper for creating DOM elements.

function createElement(tag, attributes = {}, children = []) {
const element = document.createElement(tag);
// Set attributes
Object.entries(attributes).forEach(([key, value]) => {
if (key === 'className') {
element.className = value;
} else if (key === 'dataset') {
Object.entries(value).forEach(([dataKey, dataValue]) => {
element.dataset[dataKey] = dataValue;
});
} else if (key.startsWith('on') && typeof value === 'function') {
element.addEventListener(key.slice(2).toLowerCase(), value);
} else {
element.setAttribute(key, value);
}
});
// Add children
children.forEach(child => {
if (typeof child === 'string') {
element.appendChild(document.createTextNode(child));
} else {
element.appendChild(child);
}
});
return element;
}
// Usage
const button = createElement('button', {
className: 'btn btn-primary',
dataset: { action: 'submit' },
onclick: () => console.log('Clicked!')
}, ['Submit']);
document.body.appendChild(button);

Efficient event handling for dynamic content.

function delegate(parent, selector, event, handler) {
parent.addEventListener(event, (e) => {
if (e.target.matches(selector)) {
handler.call(e.target, e);
}
});
}
// Usage
delegate(document.body, '.dynamic-button', 'click', function(e) {
console.log('Button clicked:', this.textContent);
});

Robust form validation utilities.

const validators = {
required: (value) => value.trim() !== '',
email: (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
minLength: (min) => (value) => value.length >= min,
maxLength: (max) => (value) => value.length <= max,
pattern: (regex) => (value) => regex.test(value),
numeric: (value) => !isNaN(value) && !isNaN(parseFloat(value)),
url: (value) => {
try {
new URL(value);
return true;
} catch {
return false;
}
}
};
function validateForm(data, rules) {
const errors = {};
Object.entries(rules).forEach(([field, fieldRules]) => {
const value = data[field] || '';
const fieldErrors = [];
fieldRules.forEach(rule => {
if (typeof rule === 'function') {
if (!rule(value)) fieldErrors.push('Invalid value');
} else if (typeof rule === 'object') {
const { validator, message } = rule;
if (!validator(value)) fieldErrors.push(message);
}
});
if (fieldErrors.length > 0) {
errors[field] = fieldErrors;
}
});
return {
isValid: Object.keys(errors).length === 0,
errors
};
}
// Usage
const formData = {
email: 'user@example.com',
password: '123',
website: 'https://example.com'
};
const validationRules = {
email: [
{ validator: validators.required, message: 'Email is required' },
{ validator: validators.email, message: 'Invalid email format' }
],
password: [
{ validator: validators.required, message: 'Password is required' },
{ validator: validators.minLength(8), message: 'Password must be at least 8 characters' }
],
website: [
{ validator: validators.url, message: 'Invalid URL format' }
]
};
const validation = validateForm(formData, validationRules);
console.log(validation);

Cache function results for performance optimization.

function memoize(fn) {
const cache = new Map();
return function (...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
// Usage
const expensiveFunction = memoize((n) => {
console.log('Computing for', n);
return n * n * n;
});
console.log(expensiveFunction(5)); // Computes and caches
console.log(expensiveFunction(5)); // Returns from cache

Load content only when needed.

class LazyLoader {
constructor() {
this.observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
this.loadElement(entry.target);
this.observer.unobserve(entry.target);
}
});
});
}
observe(element) {
this.observer.observe(element);
}
loadElement(element) {
if (element.dataset.src) {
element.src = element.dataset.src;
element.removeAttribute('data-src');
}
if (element.dataset.content) {
element.innerHTML = element.dataset.content;
element.removeAttribute('data-content');
}
element.classList.add('loaded');
}
}
// Usage
const lazyLoader = new LazyLoader();
document.querySelectorAll('[data-src], [data-content]').forEach((el) => {
lazyLoader.observe(el);
});

Various random number utilities.

// Random integer between min and max (inclusive)
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Random float between min and max
function randomFloat(min, max) {
return Math.random() * (max - min) + min;
}
// Random element from array
function randomChoice(array) {
return array[Math.floor(Math.random() * array.length)];
}
// Shuffle array (Fisher-Yates)
function 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;
}
// Generate random string
function randomString(length, charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
let result = '';
for (let i = 0; i < length; i++) {
result += charset.charAt(Math.floor(Math.random() * charset.length));
}
return result;
}
console.log(randomInt(1, 10)); // Random integer 1-10
console.log(randomChoice(['a', 'b', 'c'])); // Random element
console.log(shuffle([1, 2, 3, 4, 5])); // Shuffled array
console.log(randomString(8)); // Random 8-character string

This cookbook provides practical solutions for common JavaScript tasks. Each recipe is production-ready and includes explanations of the approach used.