const users = [
{ name: "Alice", age: 30, active: true },
{ name: "Bob", age: 25, active: false },
{ name: "Carol", age: 35, active: true },
];
// map: transform each element
const names = users.map(u => u.name); // ["Alice", "Bob", "Carol"]
// filter: keep matching elements
const active = users.filter(u => u.active); // [Alice, Carol]
// reduce: fold to a single value
const totalAge = users.reduce((sum, u) => sum + u.age, 0); // 90
// Chaining: active users sorted by age descending
const result = users
.filter(u => u.active)
.sort((a, b) => b.age - a.age)
.map(u => u.name);
// ["Carol", "Alice"]
// flat and flatMap
const nested = [[1, 2], [3, 4], [5]];
console.log(nested.flat()); // [1, 2, 3, 4, 5]
const sentences = ["hello world", "foo bar"];
const words = sentences.flatMap(s => s.split(" "));
// ["hello", "world", "foo", "bar"]
// findIndex, at (ES2022), Array.from
const idx = users.findIndex(u => u.name === "Bob"); // 1
console.log(users.at(-1)); // last element: Carol
JavaScriptdestructuring.jsCopyCopy
#9654; Try it
Destructuring and rest/spread
// Object destructuring with rename and default
const { name, age = 0, role: userRole = "guest" } = { name: "Alice", age: 30 };
// name = "Alice", age = 30, userRole = "guest" (renamed from role, defaulted)
// Array destructuring with skip
const [first, , third, ...rest] = [1, 2, 3, 4, 5];
// first=1, third=3, rest=[4,5]
// Nested destructuring
const { address: { city, zip } } = { address: { city: "Mumbai", zip: "400001" } };
// Function parameter destructuring
function renderUser({ name, age = 0, active = true }) {
return `${name} (${age}) — ${active ? "active" : "inactive"}`;
}
renderUser({ name: "Alice", age: 30 });
// Spread: clone and merge objects
const base = { theme: "dark", lang: "en" };
const overrides = { lang: "hi", fontSize: 16 };
const config = { ...base, ...overrides };
// { theme: "dark", lang: "hi", fontSize: 16 }
// Later properties win — overrides replaces base.lang
// Spread arrays
const a = [1, 2, 3];
const b = [0, ...a, 4]; // [0, 1, 2, 3, 4]
JavaScriptasync_patterns.jsCopyCopy
#9654; Try it
Async/await patterns and error handling
// Basic async/await
async function fetchUser(id) {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
// Sequential vs concurrent
async function sequential(ids) {
const results = [];
for (const id of ids) {
results.push(await fetchUser(id)); // waits for each
}
return results; // total time = sum of all requests
}
async function concurrent(ids) {
// Promise.all: all start immediately, wait for all to finish
return Promise.all(ids.map(id => fetchUser(id))); // total = slowest request
}
// Promise.allSettled: get results even when some fail
async function resilient(ids) {
const results = await Promise.allSettled(ids.map(fetchUser));
return results.map(r =>
r.status === "fulfilled" ? r.value : { error: r.reason.message }
);
}
// Promise.race: take the first to resolve
async function withTimeout(promise, ms) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), ms)
);
return Promise.race([promise, timeout]);
}
JavaScriptoptional_chaining.jsCopyCopy
#9654; Try it
Optional chaining and nullish coalescing
const user = {
name: "Alice",
address: {
city: "Mumbai",
},
getGreeting: () => "Hello!"
};
// Optional chaining (?.) — returns undefined instead of throwing
console.log(user.address?.city); // "Mumbai"
console.log(user.address?.zip); // undefined (no throw)
console.log(user.profile?.avatar?.url); // undefined
console.log(user.getGreeting?.()); // "Hello!"
console.log(user.nonExistent?.()); // undefined
// Array optional chaining
const arr = null;
console.log(arr?.[0]); // undefined
// Nullish coalescing (??) — only falls back on null/undefined (not 0 or "")
const count = user.postCount ?? 0; // 0 if null/undefined
const name = user.name ?? "Anonymous"; // "Alice"
const zero = 0 ?? 42; // 0 — 0 is NOT null/undefined
// vs logical OR (||) — falls back on any falsy value
const zeroOr = 0 || 42; // 42 — 0 is falsy
// Nullish assignment (??=)
user.score ??= 100; // assigns only if user.score is null/undefined
JavaScriptclasses_modern.jsCopyCopy
#9654; Try it
Classes with private fields (ES2022)
class BankAccount {
// Private fields: truly private, not just convention
#balance;
#owner;
#transactions = [];
constructor(owner, initialBalance = 0) {
this.#owner = owner;
this.#balance = initialBalance;
}
deposit(amount) {
if (amount <= 0) throw new RangeError("Amount must be positive");
this.#balance += amount;
this.#transactions.push({ type: "deposit", amount });
return this; // method chaining
}
withdraw(amount) {
if (amount > this.#balance) throw new Error("Insufficient funds");
this.#balance -= amount;
this.#transactions.push({ type: "withdrawal", amount });
return this;
}
// Getter: read-only computed property
get balance() { return this.#balance; }
get owner() { return this.#owner; }
// Static method: factory
static empty(owner) { return new BankAccount(owner, 0); }
}
const acc = BankAccount.empty("Alice").deposit(1000).withdraw(200);
console.log(acc.balance); // 800
// acc.#balance // SyntaxError: private field
JavaScriptiterators_generators.jsCopyCopy
#9654; Try it
Generators and custom iterators
// Generator function: lazy value producer
function* range(start, end, step = 1) {
for (let i = start; i < end; i += step) {
yield i;
}
}
console.log([...range(0, 10, 2)]); // [0, 2, 4, 6, 8]
for (const n of range(1, 4)) {
console.log(n); // 1, 2, 3
}
// Infinite generator
function* naturals() {
let n = 1;
while (true) yield n++;
}
function take(n, iter) {
const result = [];
for (const val of iter) {
result.push(val);
if (result.length >= n) break;
}
return result;
}
console.log(take(5, naturals())); // [1, 2, 3, 4, 5]
// Custom iterable object
const countdown = {
from: 5,
[Symbol.iterator]() {
let current = this.from;
return {
next() {
return current > 0
? { value: current--, done: false }
: { value: undefined, done: true };
}
};
}
};
console.log([...countdown]); // [5, 4, 3, 2, 1]
JavaScriptmap_set.jsCopyCopy
#9654; Try it
Map, Set, WeakMap, and WeakRef
// Map: any key type, insertion-order iteration
const map = new Map();
const keyObj = { id: 1 };
map.set(keyObj, "object key works");
map.set("string", 42);
map.set(true, "boolean key");
console.log(map.get(keyObj)); // "object key works"
console.log(map.size); // 3
// Map from entries
const freq = new Map([["a", 3], ["b", 1], ["c", 2]]);
const sorted = [...freq.entries()].sort((a, b) => b[1] - a[1]);
// [["a",3], ["c",2], ["b",1]]
// Set: unique values, insertion order
const set = new Set([1, 2, 3, 2, 1]);
console.log([...set]); // [1, 2, 3]
// Set operations (no built-in methods until ES2024)
const a = new Set([1, 2, 3, 4]);
const b = new Set([3, 4, 5, 6]);
const union = new Set([...a, ...b]);
const intersection = new Set([...a].filter(x => b.has(x)));
const difference = new Set([...a].filter(x => !b.has(x)));
// WeakMap: keys are objects, no memory leak when key is GC'd
const cache = new WeakMap();
function memoize(obj, compute) {
if (!cache.has(obj)) cache.set(obj, compute(obj));
return cache.get(obj);
}
JavaScriptobject_methods.jsCopyCopy
#9654; Try it
Object.entries, groupBy, structuredClone
const scores = { alice: 95, bob: 87, carol: 92, dave: 87 };
// Object.entries/keys/values
Object.entries(scores).forEach(([name, score]) => {
console.log(`${name}: ${score}`);
});
// Sort object by value
const ranked = Object.entries(scores)
.sort(([, a], [, b]) => b - a) // sort by value descending
.map(([name]) => name);
// ["alice", "carol", "bob", "dave"]
// Object.fromEntries: entries back to object
const doubled = Object.fromEntries(
Object.entries(scores).map(([k, v]) => [k, v * 2])
);
// Object.groupBy (ES2024)
const people = [
{ name: "Alice", dept: "eng" },
{ name: "Bob", dept: "hr" },
{ name: "Carol", dept: "eng" },
];
// const byDept = Object.groupBy(people, p => p.dept);
// { eng: [Alice, Carol], hr: [Bob] }
// structuredClone: deep clone (replaces JSON.parse(JSON.stringify(...)))
const original = { a: 1, nested: { b: [2, 3] }, date: new Date() };
const clone = structuredClone(original);
clone.nested.b.push(4);
console.log(original.nested.b); // [2, 3] — not affected
JavaScripterror_patterns.jsCopyCopy
#9654; Try it
Custom errors and error handling patterns
// Custom Error subclass
class ValidationError extends Error {
constructor(field, message) {
super(message);
this.name = "ValidationError";
this.field = field;
// Maintain proper stack trace in V8
if (Error.captureStackTrace) {
Error.captureStackTrace(this, ValidationError);
}
}
}
class NetworkError extends Error {
constructor(statusCode, message) {
super(message);
this.name = "NetworkError";
this.statusCode = statusCode;
}
}
// Error handling with instanceof
async function loadUser(id) {
try {
const user = await fetchUser(id);
return user;
} catch (error) {
if (error instanceof NetworkError && error.statusCode === 404) {
return null; // not found — not an error
}
throw error; // re-throw unexpected errors
}
}
// using declaration (ES2025 proposal — check browser support)
// try {
// await using resource = acquireResource();
// // resource.dispose() called automatically
// }
JavaScriptproxy_reflect.jsCopyCopy
#9654; Try it
Proxy for validation and observation
// Proxy: intercept object operations
function createValidated(target, validators) {
return new Proxy(target, {
set(obj, prop, value) {
if (validators[prop]) {
const error = validators[prop](value);
if (error) throw new TypeError(`${prop}: ${error}`);
}
return Reflect.set(obj, prop, value); // Reflect: default behaviour
},
get(obj, prop) {
console.log(`Reading ${prop}`);
return Reflect.get(obj, prop);
}
});
}
const user = createValidated({}, {
age: v => typeof v !== "number" ? "must be a number"
: v < 0 ? "must be non-negative"
: null,
email: v => !v.includes("@") ? "must contain @" : null,
});
user.age = 25; // ok
user.email = "a@b.c"; // ok
// user.age = -1; // TypeError: age: must be non-negative
// user.email = "bad"; // TypeError: email: must contain @
JavaScriptmodules.mjsCopyCopy
#9654; Try it
ES modules: named, default, re-export
// math.mjs — named exports
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export function multiply(a, b) { return a * b; }
// Default export: one per module
export default class Calculator {
add(a, b) { return a + b; }
}
// main.mjs — importing
import Calculator, { add, PI } from "./math.mjs";
import * as math from "./math.mjs"; // namespace import
console.log(PI); // 3.14159
console.log(add(1, 2)); // 3
console.log(math.multiply(3, 4)); // 12
// Rename on import
import { multiply as times } from "./math.mjs";
// Dynamic import: lazy load modules
async function loadFeature() {
const { heavyFunction } = await import("./heavy.mjs");
return heavyFunction();
}
// Re-export (barrel export pattern in index.mjs)
// export { add, multiply } from "./math.mjs";
// export { default as Calculator } from "./math.mjs";
JavaScripttemplate_literals.jsCopyCopy
#9654; Try it
Tagged template literals
// Tagged template: function(strings, ...values)
// Used in: styled-components, gql, sql, html sanitisation
// Safe HTML escaping
function html(strings, ...values) {
const escape = s => String(s)
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """);
return strings.reduce((result, str, i) =>
result + str + (values[i] !== undefined ? escape(values[i]) : ""), ""
);
}
const userInput = '<script>alert("xss")</script>';
const safe = html`<p>Hello, ${userInput}!</p>`;
// <p>Hello, <script>alert("xss")</script>!</p>
// SQL tag (pattern — implement with your DB client)
function sql(strings, ...values) {
const query = strings.reduce((q, str, i) => q + str + (i < values.length ? `$${i+1}` : ""), "");
return { query, params: values };
}
const userId = 42;
const { query, params } = sql`SELECT * FROM users WHERE id = ${userId}`;
// query: "SELECT * FROM users WHERE id = $1"
// params: [42]