JavaScript Tips
Practical JavaScript tips, patterns, and modern ES6+ features.
20 tips
Optional Chaining
BasicsSafely access deeply nested properties without throwing if intermediate values are null/undefined.
obj?.nested?.propNullish Coalescing
BasicsReturns the right operand when the left is null or undefined (but not 0 or empty string).
const val = input ?? "default";Destructuring with Rename
BasicsExtract object properties into variables with custom names.
const { name: userName, age } = user;Spread & Rest
BasicsSpread expands iterables; rest collects remaining elements into an array or object.
const { id, ...rest } = obj;
const merged = { ...a, ...b };Object.groupBy()
ES2024+Group array items by a key function. Returns an object whose keys are group names.
const grouped = Object.groupBy(users, u => u.role);Array.toSorted()
ES2024+Returns a new sorted array without mutating the original. Also: toReversed(), toSpliced().
const sorted = nums.toSorted((a, b) => a - b);structuredClone()
ES2024+Deep clone any serializable value — handles nested objects, arrays, Maps, Sets, Dates.
const copy = structuredClone(deepObject);Array.flat() & flatMap()
ArraysFlatten nested arrays or map then flatten in one step.
[[1,2],[3,4]].flat(Infinity);
[1,2,3].flatMap(x => [x, x*2]);Array.at()
ArraysAccess array elements by index — supports negative indices to count from the end.
const last = arr.at(-1);Array Reduce
ArraysCommon reduce patterns: sum, group-by, flatten, frequency count.
nums.reduce((sum, n) => sum + n, 0);Template Literals
StringsEmbed expressions in strings with backticks. Supports multi-line strings.
const url = `https://api.com/users/${id}`;String.replaceAll()
StringsReplace all occurrences of a substring without regex.
"foo-bar-baz".replaceAll("-", "_"); // "foo_bar_baz"async/await
AsyncWrap await calls in try/catch for clean error handling.
async function load() {
try {
const res = await fetch("/api/data");
return await res.json();
} catch (err) { console.error(err); }
}Promise.allSettled()
AsyncWait for all promises regardless of outcome.
const results = await Promise.allSettled([fetch("/a"), fetch("/b")]);
results.filter(r => r.status === "fulfilled");AbortController
AsyncCancel fetch requests or any AbortSignal-aware API.
const ctrl = new AbortController();
setTimeout(() => ctrl.abort(), 5000);
const res = await fetch(url, { signal: ctrl.signal });querySelector & classList
DOMSelect elements with CSS selectors and manipulate classes.
const el = document.querySelector(".card");
el.classList.toggle("hidden");IntersectionObserver
DOMDetect when elements enter/leave the viewport — ideal for lazy loading.
const obs = new IntersectionObserver(entries =>
entries.forEach(e => e.target.classList.toggle("visible", e.isIntersecting))
);
obs.observe(el);Event Delegation
DOMAttach one listener to a parent instead of many to children.
document.querySelector("ul").addEventListener("click", e => {
if (e.target.matches("li")) console.log(e.target.textContent);
});Debounce
PatternsDelay execution until a pause in events — ideal for search input.
function debounce(fn, ms) {
let t;
return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), ms); };
}Memoization
PatternsCache expensive function results based on arguments.
function memoize(fn) {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (!cache.has(key)) cache.set(key, fn(...args));
return cache.get(key);
};
}All processing happens locally in your browser. No data is sent to any server.