// ── Arrow Functions ──
const add = (a, b) => a + b;
const square = x => x * x;
const greet = () => "Hello!";
// Arrow vs regular: no own this, arguments, super, new.target
const obj = {
value: 42,
regular() { return this.value; }, // 42 (lexical this)
arrow: () => { return this.value; }, // undefined in strict mode
};
// ── Default Parameters ──
function createUser(name, role = "user", active = true) {
return { name, role, active };
}
createUser("Alice"); // { name: "Alice", role: "user", active: true }
createUser("Bob", "admin"); // { name: "Bob", role: "admin", active: true }
// ── Rest Parameters ──
function sum(...numbers) {
return numbers.reduce((acc, n) => acc + n, 0);
}
sum(1, 2, 3, 4); // 10
// ── Closures ──
function createCounter(initial = 0) {
let count = initial;
return {
increment: () => ++count,
decrement: () => --count,
getCount: () => count,
reset: () => { count = initial; },
};
}
const counter = createCounter(10);
counter.increment(); // 11
counter.increment(); // 12
counter.getCount(); // 12
// ── IIFE (Immediately Invoked Function Expression) ──
(function() {
const secret = "hidden";
console.log(secret); // only accessible inside
})();
(() => {
const x = 42;
console.log(x);
})();
// ── Callbacks ──
function fetchData(url, onSuccess, onError) {
fetch(url)
.then(res => res.json())
.then(data => onSuccess(data))
.catch(err => onError(err));
}
// ── Generators ──
function* idGenerator() {
let id = 1;
while (true) {
yield id++;
}
}
const gen = idGenerator();
gen.next().value; // 1
gen.next().value; // 2
gen.next().value; // 3
function* range(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
[...range(1, 5)]; // [1, 2, 3, 4, 5]
// ── Async/Await ──
async function fetchUser(id) {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) throw new Error("User not found");
const user = await response.json();
return user;
} catch (error) {
console.error("Failed to fetch user:", error);
throw error;
}
}
// Parallel execution
async function fetchMultiple() {
const [users, posts] = await Promise.all([
fetch("/api/users").then(r => r.json()),
fetch("/api/posts").then(r => r.json()),
]);
return { users, posts };
}
// ── this keyword ──
// In a method: this = the owner object
const user = {
name: "Alice",
greet() { return `Hello, ${this.name}`; },
};
user.greet(); // "Hello, Alice"
// ── bind, call, apply ──
function introduce(greeting) {
return `${greeting}, I am ${this.name}`;
}
const bob = { name: "Bob" };
introduce.call(bob, "Hi"); // "Hi, I am Bob"
introduce.apply(bob, ["Hi"]); // "Hi, I am Bob"
const bound = introduce.bind(bob);
bound("Hey"); // "Hey, I am Bob"
// bind for event handlers
class Button {
constructor(label) {
this.label = label;
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log(this.label);
}
}
| Type | Syntax | Own this |
|---|
| Declaration | function f() {} | Yes |
| Expression | const f = function() {} | Yes |
| Arrow | const f = () => {} | No (inherits) |
| Generator | function* f() {} | Yes |
| Async | async function f() {} | Yes |
| Async arrow | const f = async () => {} | No |
| IIFE | (function() {})() | Yes |
| Method | Invokes Now? | Arguments | Returns |
|---|
| call(this, a, b) | Yes | List: a, b | Result |
| apply(this, [a, b]) | Yes | Array: [a, b] | Result |
| bind(this, a) | No | List: a | New fn |
⚠️Arrow functions do not have their own this — they inherit this from the enclosing scope. This makes them perfect for callbacks but wrong for object methods or class constructors. Use .bind(this) or arrow class properties when passing methods as callbacks.
// ── map, filter, reduce ──
const numbers = [1, 2, 3, 4, 5, 6];
const doubled = numbers.map(n => n * 2);
// [2, 4, 6, 8, 10, 12]
const evens = numbers.filter(n => n % 2 === 0);
// [2, 4, 6]
const sum = numbers.reduce((acc, n) => acc + n, 0);
// 21
const grouped = numbers.reduce((acc, n) => {
const key = n % 2 === 0 ? "even" : "odd";
acc[key] = [...(acc[key] || []), n];
return acc;
}, {});
// { odd: [1, 3, 5], even: [2, 4, 6] }
// ── find, findIndex, some, every ──
const users = [
{ id: 1, name: "Alice", active: true },
{ id: 2, name: "Bob", active: false },
{ id: 3, name: "Charlie", active: true },
];
users.find(u => u.name === "Bob"); // { id: 2, name: "Bob", ... }
users.findIndex(u => u.id === 3); // 2
users.some(u => u.active); // true
users.every(u => u.active); // false
// ── flat, flatMap ──
const nested = [[1, 2], [3, [4, 5]]];
nested.flat(); // [1, 2, 3, [4, 5]]
nested.flat(Infinity); // [1, 2, 3, 4, 5]
const sentences = ["hello world", "foo bar"];
sentences.flatMap(s => s.split(" "));
// ["hello", "world", "foo", "bar"]
// ── sort (mutates! use toSorted for immutable) ──
const nums = [3, 1, 4, 1, 5, 9];
const sorted = nums.toSorted((a, b) => a - b); // [1, 1, 3, 4, 5, 9]
// nums is still [3, 1, 4, 1, 5, 9]
const byName = users.toSorted((a, b) =>
a.name.localeCompare(b.name)
);
// ── slice, splice, concat ──
const arr = [1, 2, 3, 4, 5];
arr.slice(1, 3); // [2, 3] (no mutation)
arr.splice(1, 2, 99); // removes 2 items at index 1, inserts 99 (mutates!)
arr.concat([6, 7]); // [1, 99, 4, 5, 6, 7] (no mutation)
// ── Other useful methods ──
[1, 2, 3].includes(2); // true
[1, 2, 3].indexOf(2); // 1
[1, 2, 3, 2].lastIndexOf(2); // 3
[1, 2, 3].join("-"); // "1-2-3"
[3, 1, 2].fill(0, 1, 3); // [3, 0, 0]
Array.from("hello"); // ["h", "e", "l", "l", "o"]
Array.from({ length: 5 }, (_, i) => i); // [0, 1, 2, 3, 4]
// ── Object methods ──
const person = { name: "Alice", age: 30, city: "NYC" };
Object.keys(person); // ["name", "age", "city"]
Object.values(person); // ["Alice", 30, "NYC"]
Object.entries(person); // [["name","Alice"], ["age",30], ...]
const clone = { ...person }; // shallow clone
const merged = Object.assign({}, person, { age: 31 });
// ── Destructuring ──
const { name, age, city = "Unknown" } = person;
const { name: userName, ...rest } = person;
// Array destructuring
const [first, second, ...others] = [1, 2, 3, 4, 5];
const [a, b] = [1, 2];
[a, b] = [b, a]; // swap without temp variable
// Nested destructuring
const { address: { street, zip } } = {
name: "Alice", address: { street: "123 Main", zip: "10001" },
};
// Destructuring in function params
function drawChart({ width = 800, height = 600, color = "blue" } = {}) {
return `Chart: ${width}x${height}, color: ${color}`;
}
// ── Optional Chaining (?.) ──
const user = { profile: { address: { city: "NYC" } } };
user.profile?.address?.city; // "NYC"
user.settings?.theme; // undefined (no error)
user.getAvatar?.(); // undefined if method doesn't exist
// ── Nullish Coalescing (??) ──
const value = null ?? "default"; // "default"
const count = 0 ?? 42; // 0 (0 is not null/undefined)
const name = "" ?? "Anonymous"; // "" (not nullish)
// ?? vs || : || treats 0, "", false as falsy
0 || 42; // 42
0 ?? 42; // 0
"" || "hi"; // "hi"
"" ?? "hi"; // ""
// ── Spread with objects ──
const defaults = { theme: "light", lang: "en", debug: false };
const userPrefs = { theme: "dark", lang: "fr" };
const config = { ...defaults, ...userPrefs };
// { theme: "dark", lang: "fr", debug: false }
| Method | Returns | Mutates |
|---|
| map(fn) | New array | No |
| filter(fn) | New array | No |
| reduce(fn, init) | Accumulated value | No |
| find(fn) | First match or undefined | No |
| findIndex(fn) | Index or -1 | No |
| some(fn) | Boolean | No |
| every(fn) | Boolean | No |
| flat(depth) | New flat array | No |
| sort(fn) | Same array | Yes |
| splice(start, del) | Removed elements | Yes |
| toSorted(fn) | New sorted array | No |
| toReversed() | New reversed array | No |
| toSpliced(start, del) | New array | No |
| Method | Description |
|---|
| Object.keys(obj) | Array of own enumerable keys |
| Object.values(obj) | Array of own enumerable values |
| Object.entries(obj) | Array of [key, value] pairs |
| Object.assign(target, src) | Merge (mutates target) |
| Object.freeze(obj) | Make immutable (shallow) |
| Object.seal(obj) | No add/delete, allow update |
| Object.fromEntries(arr) | Create obj from [k,v] array |
| Object.is(v1, v2) | Strict equality (NaN === NaN) |
| Object.hasOwn(obj, key) | Safe hasOwnProperty |
💡Use toSorted(), toReversed(), and toSpliced() (ES2023) instead of sort(), reverse(), splice() when you need immutable operations. They return new arrays without modifying the original.
// ── Querying Elements ──
document.getElementById("app");
document.querySelector(".card"); // first match
document.querySelectorAll(".card"); // all matches (NodeList)
document.querySelectorAll("div.card > p"); // complex selector
// Traversal
const el = document.querySelector(".card");
el.parentElement; // parent element
el.children; // HTMLCollection of child elements
el.nextElementSibling; // next sibling element
el.previousElementSibling; // previous sibling element
el.closest(".container"); // nearest ancestor matching selector
// ── Creating & Modifying ──
const div = document.createElement("div");
div.textContent = "Hello";
div.innerHTML = "<strong>Bold</strong>";
div.setAttribute("data-id", "123");
document.body.appendChild(div);
document.body.insertBefore(div, referenceNode);
referenceNode.insertAdjacentElement("beforebegin", div);
// beforebegin | afterbegin | beforeend | afterend
const clone = div.cloneNode(true); // true = deep clone
div.remove(); // remove from DOM
// ── Event Listeners ──
const btn = document.querySelector("#submit");
btn.addEventListener("click", (event) => {
event.preventDefault(); // stop default action
event.stopPropagation(); // stop bubbling
console.log(event.target); // element that triggered
console.log(event.currentTarget); // element with listener
});
btn.addEventListener("click", handleClick);
btn.removeEventListener("click", handleClick);
// ── Event Delegation ──
document.querySelector(".list").addEventListener("click", (e) => {
const item = e.target.closest(".list-item");
if (!item) return;
console.log("Clicked item:", item.dataset.id);
});
// ── Custom Events ──
const event = new CustomEvent("userLogin", {
detail: { userId: 42, timestamp: Date.now() },
bubbles: true,
});
document.dispatchEvent(event);
document.addEventListener("userLogin", (e) => {
console.log("User logged in:", e.detail.userId);
});
// ── classList API ──
el.classList.add("active", "visible");
el.classList.remove("hidden");
el.classList.toggle("dark-mode");
el.classList.contains("active"); // true/false
el.classList.replace("old-class", "new-class");
// ── dataset (data-attributes) ──
// <div data-user-id="42" data-role="admin" />
el.dataset.userId; // "42"
el.dataset.role; // "admin"
el.dataset.newProp = "value"; // sets data-new-prop
// ── Style manipulation ──
el.style.backgroundColor = "blue";
el.style.setProperty("--custom-color", "red");
const computed = getComputedStyle(el);
computed.getPropertyValue("--custom-color");
// ── Intersection Observer ──
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add("visible");
observer.unobserve(entry.target);
}
});
}, { threshold: 0.5 });
document.querySelectorAll(".lazy-element").forEach(el => {
observer.observe(el);
});
// ── Mutation Observer ──
const mutObserver = new MutationObserver((mutations) => {
mutations.forEach(m => {
console.log("Changed:", m.type, m.target);
});
});
mutObserver.observe(document.body, {
childList: true, // watch child additions/removals
attributes: true, // watch attribute changes
subtree: true, // watch entire subtree
});
// mutObserver.disconnect(); // stop observing
| Position | Location |
|---|
| beforebegin | Before the element itself |
| afterbegin | Just inside, before first child |
| beforeend | Just inside, after last child |
| afterend | After the element itself |
| Option | Description |
|---|
| threshold | 0-1: fraction visible to trigger |
| root | Viewport or element to observe against |
| rootMargin | CSS margin to expand/ shrink root box |
💡Use event delegation on parent containers instead of attaching listeners to every child element. It is more performant and automatically handles dynamically added elements via e.target.closest(selector).
// ── Template Literals ──
const name = "Alice";
const age = 30;
const greeting = `Hello, ${name}! You are ${age} years old.`;
// Tagged templates
function highlight(strings, ...values) {
return strings.reduce((result, str, i) => {
const val = values[i] ? `<mark>${values[i]}</mark>` : "";
return result + str + val;
}, "");
}
highlight`Hello ${name}, you have ${5} new messages.`;
// "Hello <mark>Alice</mark>, you have <mark>5</mark> new messages."
// ── Computed Properties ──
const key = "color";
const styles = {
[key]: "blue",
[`${key}Hover`]: "darkblue",
};
// { color: "blue", colorHover: "darkblue" }
// ── Shorthand Properties ──
const x = 1, y = 2;
const point = { x, y };
// Same as: { x: x, y: y }
const obj = {
*generator() { yield 1; }, // computed generator
async method() {}, // async method
get value() { return 42; }, // getter
set value(v) { }, // setter
};
// ── ES Modules (import / export) ──
// math.js
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export default class Calculator { /* ... */ }
// app.js
import Calculator, { PI, add } from "./math.js";
import * as math from "./math.js";
import { add as sum } from "./math.js";
// Dynamic import
const module = await import("./heavy-module.js");
module.doSomething();
// ── Symbol ──
const id = Symbol("uniqueId");
const hidden = Symbol("hidden");
const user = {
name: "Alice",
[id]: 42,
[hidden]: "secret",
};
Object.keys(user); // ["name"]
Object.getOwnPropertySymbols(user); // [Symbol(uniqueId), Symbol(hidden)]
// Well-known symbols
const iterable = {
[Symbol.iterator]() {
let i = 0;
return { next: () => ({ done: i >= 3, value: i++ }) };
},
};
[...iterable]; // [0, 1, 2]
// ── Map ──
const map = new Map();
map.set("key", "value");
map.set(42, "number key");
map.set({}, "object key"); // any type as key
map.get("key"); // "value"
map.has("key"); // true
map.size; // 3
map.delete("key");
map.clear();
const fromObj = new Map(Object.entries({ a: 1, b: 2 }));
// ── Set ──
const set = new Set([1, 2, 3, 2, 1]);
// Set {1, 2, 3}
set.add(4);
set.has(3); // true
set.size; // 4
set.delete(2);
// Unique values from array
const unique = [...new Set([1, 2, 3, 2, 1])]; // [1, 2, 3]
// Set operations (ES2024+)
const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);
a.union(b); // Set {1, 2, 3, 4}
a.intersection(b); // Set {2, 3}
a.difference(b); // Set {1}
// ── WeakMap & WeakSet (keys must be objects, GC-friendly) ──
const wm = new WeakMap();
const obj = {};
wm.set(obj, "metadata");
wm.get(obj); // "metadata"
// obj can be garbage collected when no other references exist
// ── Promise.all, allSettled, race, any ──
const p1 = fetch("/api/users").then(r => r.json());
const p2 = fetch("/api/posts").then(r => r.json());
const p3 = fetch("/api/comments").then(r => r.json());
// All must resolve (fails fast on first rejection)
const [users, posts, comments] = await Promise.all([p1, p2, p3]);
// All settle (never rejects, always resolves with status)
const results = await Promise.allSettled([p1, p2, p3]);
results.forEach(r => {
if (r.status === "fulfilled") console.log(r.value);
else console.error(r.reason);
});
// First to settle (resolve or reject)
const first = await Promise.race([p1, p2, p3]);
// First to fulfill (ignores rejections until all reject)
const any = await Promise.any([p1, p2, p3]);
// ── for...of ──
for (const [key, value] of map) { /* ... */ }
for (const item of set) { /* ... */ }
for (const char of "hello") { /* ... */ }
| Feature | Object | Map |
|---|
| Key types | Strings/Symbols | Any type |
| Key order | Integer keys first | Insertion order |
| Size | Object.keys().length | map.size (O(1)) |
| Iteration | for...in, Object.entries | for...of |
| Prototype | Has (toString, etc.) | No prototype |
| Performance | Optimized for simple keys | Frequent add/delete |
| Method | Rejects when | Use case |
|---|
| Promise.all() | Any rejects | All must succeed |
| Promise.allSettled() | Never | Check each result |
| Promise.race() | Any settles | Timeout pattern |
| Promise.any() | All reject | First success wins |
⚠️Use Promise.allSettled() when you need results from all promises regardless of individual failures. Use Promise.all() only when all promises must succeed for the operation to be meaningful.
// ── try / catch / finally ──
try {
const data = JSON.parse(input);
if (!data.name) throw new Error("Name is required");
} catch (error) {
if (error instanceof SyntaxError) {
console.error("Invalid JSON:", error.message);
} else {
console.error("Custom error:", error.message);
}
} finally {
// Always runs (even after return/throw)
console.log("Cleanup complete");
}
// ── Custom Errors ──
class AppError extends Error {
constructor(message, statusCode, code) {
super(message);
this.name = this.constructor.name;
this.statusCode = statusCode;
this.code = code;
}
}
class ValidationError extends AppError {
constructor(field, message) {
super(message, 400, "VALIDATION_ERROR");
this.field = field;
}
}
class NotFoundError extends AppError {
constructor(resource = "Resource") {
super(`${resource} not found`, 404, "NOT_FOUND");
}
}
throw new ValidationError("email", "Invalid email format");
throw new NotFoundError("User");
// ── Async Error Patterns ──
// Pattern 1: try/catch with async/await
async function fetchUser(id) {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) {
throw new NotFoundError("User");
}
return await res.json();
} catch (error) {
if (error instanceof NotFoundError) {
throw error; // re-throw known errors
}
throw new AppError("Failed to fetch user", 500, "FETCH_ERROR");
}
}
// Pattern 2: Error wrapper utility
function withErrorHandling(fn) {
return async (...args) => {
try {
return await fn(...args);
} catch (error) {
console.error(`Error in ${fn.name}:`, error.message);
return null;
}
};
}
// ── Error boundaries (async event handlers) ──
window.addEventListener("unhandledrejection", (event) => {
console.error("Unhandled promise rejection:", event.reason);
event.preventDefault(); // prevent default browser logging
});
window.addEventListener("error", (event) => {
console.error("Global error:", event.error);
});
// ── Console Methods ──
console.log("Basic log");
console.error("Error message");
console.warn("Warning message");
console.table([{ name: "Alice", age: 30 }]); // renders as table
console.time("fetch");
await fetch("/api/data");
console.timeEnd("fetch"); // fetch: 142ms
console.group("User Details");
console.log("Name:", name);
console.groupEnd();
console.assert(x > 0, "x must be positive");
console.count("clicks"); // clicks: 1
console.countReset("clicks");
console.trace("Call stack trace");
// ── Debugger Statement ──
function inspect(obj) {
debugger; // pauses execution in DevTools
return obj;
}
| Error Type | When Thrown |
|---|
| Error | Generic error (base class) |
| TypeError | Wrong type operation |
| ReferenceError | Undeclared variable |
| SyntaxError | Invalid JS syntax |
| RangeError | Value out of range |
| URIError | Malformed URI function |
| EvalError | Error in eval() (legacy) |
| AggregateError | Multiple errors (Promise.any) |
messageHuman-readable error description
nameError type (e.g. TypeError)
stackFull call stack trace
causeNested cause (ES2022)
🚫Never swallow errors silently. Empty catch blocks catch hide bugs. At minimum, log the error or add a TODO comment. For async code, always handle rejections — unhandled rejections crash Node.js processes.
// ── Fetch API ──
// GET request
const res = await fetch("/api/users", {
headers: { "Authorization": "Bearer token123" },
});
const data = await res.json();
// POST request
const response = await fetch("/api/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Alice", email: "alice@example.com" }),
});
// AbortController (cancel fetch)
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
try {
await fetch("/api/slow", { signal: controller.signal });
} catch (err) {
if (err.name === "AbortError") console.log("Request timed out");
} finally {
clearTimeout(timeout);
}
// Retry with exponential backoff
async function fetchWithRetry(url, retries = 3, delay = 1000) {
try {
return await fetch(url);
} catch (err) {
if (retries <= 0) throw err;
await new Promise(r => setTimeout(r, delay));
return fetchWithRetry(url, retries - 1, delay * 2);
}
}
// ── localStorage / sessionStorage ──
// localStorage persists across browser sessions
localStorage.setItem("theme", "dark");
localStorage.getItem("theme"); // "dark"
localStorage.removeItem("theme");
localStorage.clear();
localStorage.length;
// Store objects/arrays (must serialize)
localStorage.setItem("user", JSON.stringify({ name: "Alice" }));
const user = JSON.parse(localStorage.getItem("user"));
// sessionStorage: cleared when tab closes
sessionStorage.setItem("tabData", "temp");
// Storage event (fires in OTHER tabs)
window.addEventListener("storage", (e) => {
console.log("Key:", e.key, "Old:", e.oldValue, "New:", e.newValue);
});
// ── FormData ──
const form = document.querySelector("#upload-form");
const formData = new FormData(form);
formData.append("file", fileInput.files[0]);
formData.append("metadata", JSON.stringify({ title: "Photo" }));
const uploadRes = await fetch("/api/upload", {
method: "POST",
body: formData, // browser sets Content-Type with boundary
});
// ── URL / URLSearchParams ──
const url = new URL("https://example.com/path?q=hello&lang=en");
url.searchParams.get("q"); // "hello"
url.searchParams.has("lang"); // true
url.searchParams.set("page", "2");
url.searchParams.delete("lang");
url.searchParams.toString(); // "?q=hello&page=2"
url.pathname; // "/path"
url.origin; // "https://example.com"
// ── Web Workers (background threads) ──
// main.js
const worker = new Worker("worker.js");
worker.postMessage({ type: "compute", data: [1, 2, 3] });
worker.onmessage = (e) => {
console.log("Result from worker:", e.data);
};
worker.terminate();
// worker.js
self.onmessage = (e) => {
if (e.data.type === "compute") {
const result = heavyComputation(e.data.data);
self.postMessage({ result });
}
};
// ── WebSockets ──
const socket = new WebSocket("wss://example.com/ws");
socket.onopen = () => {
console.log("Connected");
socket.send(JSON.stringify({ type: "subscribe", channel: "news" }));
};
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log("Received:", data);
};
socket.onerror = (err) => console.error("WebSocket error:", err);
socket.onclose = (event) => console.log("Disconnected:", event.code);
socket.close();
// ── Clipboard API ──
await navigator.clipboard.writeText("Hello, world!");
const text = await navigator.clipboard.readText();
// ── ResizeObserver ──
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
const { width, height } = entry.contentRect;
console.log("Resized to:", width, "x", height);
}
});
resizeObserver.observe(document.querySelector(".box"));
// ── Geolocation API ──
navigator.geolocation.getCurrentPosition(
(pos) => console.log("Lat:", pos.coords.latitude, "Lng:", pos.coords.longitude),
(err) => console.error("Geolocation error:", err.message),
{ enableHighAccuracy: true, timeout: 10000 }
);
| Feature | localStorage | sessionStorage | Cookie |
|---|
| Capacity | ~5-10 MB | ~5-10 MB | ~4 KB |
| Sent to server | No | No | Yes (HTTP) |
| Expires | Manual clear | Tab close | Set expiry |
| Scope | Origin | Tab | Domain/path |
| Code | Meaning |
|---|
| 1000 | Normal closure |
| 1001 | Going away (tab close) |
| 1006 | Abnormal closure |
| 1011 | Internal server error |
| 1012 | Server restarting |
| 1013 | Try again later |
💡Use AbortController for all fetch requests that might need cancellation (component unmount, user navigation, timeout). It is the standard way to cancel any async operation in the browser.
// ── Module Pattern ──
const UserService = (() => {
let instance = null;
// Private
const cache = new Map();
async function fetchUser(id) {
if (cache.has(id)) return cache.get(id);
const res = await fetch(`/api/users/${id}`);
const user = await res.json();
cache.set(id, user);
return user;
}
function clearCache() {
cache.clear();
}
// Public API
return {
getUser: fetchUser,
clearCache,
};
})();
UserService.getUser(42);
UserService.clearCache();
// ── Singleton Pattern ──
class Database {
constructor() {
if (Database.instance) return Database.instance;
this.connection = "connected";
Database.instance = this;
}
static getInstance() {
if (!Database.instance) new Database();
return Database.instance;
}
}
const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2); // true
// ── Debounce (delay until idle) ──
function debounce(fn, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
const searchInput = document.querySelector("#search");
searchInput.addEventListener("input", debounce((e) => {
console.log("Searching:", e.target.value);
}, 300));
// ── Throttle (max once per interval) ──
function throttle(fn, limit) {
let inThrottle = false;
return function (...args) {
if (!inThrottle) {
fn.apply(this, args);
inThrottle = true;
setTimeout(() => { inThrottle = false; }, limit);
}
};
}
window.addEventListener("scroll", throttle(() => {
console.log("Scroll position:", window.scrollY);
}, 100));
// ── Memoization ──
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;
};
}
const expensiveCalc = memoize((n) => {
console.log("Computing...");
return n * n;
});
expensiveCalc(5); // "Computing..." -> 25
expensiveCalc(5); // 25 (cached)
// ── Currying ──
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) return fn(...args);
return (...moreArgs) => curried(...args, ...moreArgs);
};
}
const add = curry((a, b, c) => a + b + c);
add(1)(2)(3); // 6
add(1, 2)(3); // 6
add(1)(2, 3); // 6
add(1, 2, 3); // 6
// Practical currying
const multiply = curry((a, b) => a * b);
multiply(2)(5); // 10
// ── Composition ──
const compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x);
const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x);
const trim = (s) => s.trim();
const lowercase = (s) => s.toLowerCase();
const split = (sep) => (s) => s.split(sep);
const filterEmpty = (arr) => arr.filter(Boolean);
const processInput = pipe(trim, lowercase, split(" "), filterEmpty);
processInput(" Hello World "); // ["hello", "world"]
// ── Deep Clone ──
// Modern (Web API): handles Dates, RegExps, Maps, Sets, circular refs
const cloned = structuredClone(original);
// Manual approach
function deepClone(obj) {
if (obj === null || typeof obj !== "object") return obj;
if (obj instanceof Date) return new Date(obj);
if (Array.isArray(obj)) return obj.map(deepClone);
return Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k, deepClone(v)])
);
}
// ── Observer (Event Emitter) Pattern ──
class EventEmitter {
#events = new Map();
on(event, listener) {
if (!this.#events.has(event)) this.#events.set(event, []);
this.#events.get(event).push(listener);
return () => this.off(event, listener); // unsubscribe fn
}
off(event, listener) {
const listeners = this.#events.get(event);
if (listeners) {
const idx = listeners.indexOf(listener);
if (idx > -1) listeners.splice(idx, 1);
}
}
emit(event, ...args) {
const listeners = this.#events.get(event);
if (listeners) listeners.forEach(fn => fn(...args));
}
once(event, listener) {
const unsubscribe = this.on(event, (...args) => {
unsubscribe();
listener(...args);
});
return unsubscribe;
}
}
const emitter = new EventEmitter();
const unsub = emitter.on("data", (data) => console.log("Data:", data));
emitter.emit("data", { id: 1 }); // Data: { id: 1 }
unsub(); // stop listening
emitter.emit("data", { id: 2 }); // nothing logged
| Principle | JavaScript Application |
|---|
| Single Responsibility | One reason to change per function/module |
| Open/Closed | Extend via composition, not modification |
| Liskov Substitution | Subtypes must be substitutable for base |
| Interface Segregation | Small, focused exports per module |
| Dependency Inversion | Depend on abstractions, not concretions |
=== vs ==Always use strict equality
const > letDefault to const, use let sparingly
No varAvoid function-scoped var
DestructureCleaner access to props and data
Early returnsReduce nesting, flatten logic
Optional chainingUse ?. instead of && chains
ImmutabilityPrefer toSorted/toReversed over mutations
Error handlingNever swallow errors silently
💡Use structuredClone() (built-in Web API) instead of JSON.parse(JSON.stringify(obj)) for deep cloning. It handles Dates, RegExps, Maps, Sets, ArrayBuffers, and circular references correctly. For very simple objects, spread {...}obj is sufficient for shallow cloning.