JavaScript powers every modern web app. This reference covers the entire language — variables through async patterns — with copy-ready code you can use right now.
Quick reference
The 25 patterns that cover 90% of everyday JavaScript.
| Pattern | What it does |
|---|---|
let x = 5 |
Mutable variable |
const PI = 3.14 |
Immutable binding |
typeof x |
Get type as string |
x ?? 'default' |
Nullish coalescing |
x?.y?.z |
Optional chaining |
[...arr] |
Spread / shallow copy |
{ ...obj } |
Object spread |
const { a, b } = obj |
Object destructuring |
const [x, y] = arr |
Array destructuring |
`Hello ${name}` |
Template literal |
arr.map(fn) |
Transform each element |
arr.filter(fn) |
Keep matching elements |
arr.reduce(fn, init) |
Fold to single value |
arr.find(fn) |
First matching element |
Object.keys(obj) |
Array of keys |
Object.entries(obj) |
Array of [key, value] pairs |
Promise.all([...]) |
Await all promises |
async function f(){} |
Async function |
await fetch(url) |
Await HTTP response |
class Foo { } |
Class declaration |
import { x } from './m' |
Named import |
export default fn |
Default export |
try { } catch (e) { } |
Error handling |
setTimeout(fn, ms) |
Run later |
JSON.parse(str) |
Parse JSON string |
Variables and data types
Declaration keywords
var name = 'old'; // function-scoped, hoisted — avoid
let count = 0; // block-scoped, reassignable
const PI = 3.14159; // block-scoped, not reassignable (binding)
Rule of thumb: always const; use let when you need to reassign; never var.
Primitive types
// Seven primitives
let n = 42; // number
let big = 9007199254740993n; // bigint
let str = 'hello'; // string
let bool = true; // boolean
let nothing = null; // null (intentional absence)
let missing; // undefined (uninitialized)
let id = Symbol('uid'); // symbol (unique key)
// Check type
typeof 42 // 'number'
typeof 'hi' // 'string'
typeof null // 'object' — historical quirk
typeof undefined // 'undefined'
typeof Symbol() // 'symbol'
Array.isArray([]) // true
Type coercion and comparison
// Always use === (strict equality)
0 == false // true — avoid
0 === false // false — correct
null == undefined // true
null === undefined // false
// Truthy / falsy values
// Falsy: false, 0, -0, 0n, '', null, undefined, NaN
// Truthy: everything else, including [], {}, '0', 'false'
Boolean(0) // false
Boolean([]) // true
Boolean('') // false
Boolean(' ') // true
Strings
const s = 'Hello, World!';
// Length and access
s.length // 13
s[0] // 'H'
s.at(-1) // '!' — last character (ES2022)
// Search
s.includes('World') // true
s.startsWith('Hello') // true
s.endsWith('!') // true
s.indexOf('o') // 4
s.lastIndexOf('o') // 8
// Extract
s.slice(7, 12) // 'World'
s.slice(-6) // 'World!'
s.substring(7, 12) // 'World'
// Transform
s.toLowerCase() // 'hello, world!'
s.toUpperCase() // 'HELLO, WORLD!'
s.trim() // removes leading/trailing whitespace
s.trimStart()
s.trimEnd()
s.replace('World', 'JS') // 'Hello, JS!'
s.replaceAll('l', 'L') // 'HeLLo, WorLd!'
s.split(', ') // ['Hello', 'World!']
s.repeat(2) // 'Hello, World!Hello, World!'
s.padStart(15, '-') // '--Hello, World!'
s.padEnd(15, '-') // 'Hello, World!--'
// Template literals
const name = 'Alice';
const age = 30;
`${name} is ${age} years old` // 'Alice is 30 years old'
`Line 1
Line 2` // multi-line string
// Tagged templates
function highlight(strings, ...vals) {
return strings.reduce((acc, str, i) =>
acc + str + (vals[i] !== undefined ? `<b>${vals[i]}</b>` : ''), '');
}
highlight`Hello ${name}, you are ${age}!`
// 'Hello <b>Alice</b>, you are <b>30</b>!'
Numbers
// Arithmetic
5 + 3 // 8
10 - 4 // 6
3 * 7 // 21
15 / 4 // 3.75
15 % 4 // 3 (remainder)
2 ** 10 // 1024 (exponentiation)
// Math utilities
Math.round(4.6) // 5
Math.floor(4.9) // 4
Math.ceil(4.1) // 5
Math.abs(-7) // 7
Math.max(1, 5, 3) // 5
Math.min(1, 5, 3) // 1
Math.sqrt(16) // 4
Math.pow(2, 8) // 256
Math.random() // 0 ≤ n < 1
// Parsing
parseInt('42px') // 42
parseInt('0xFF', 16) // 255
parseFloat('3.14em') // 3.14
Number('42') // 42
Number('') // 0
Number('abc') // NaN
// Special values
Infinity
-Infinity
NaN // Not a Number
isNaN(NaN) // true
isFinite(1/0) // false
Number.isInteger(4.0) // true
// Formatting
(1234567.89).toFixed(2) // '1234567.89'
(1234567.89).toLocaleString() // '1,234,567.89' (locale-dependent)
Control flow
Conditionals
// if / else if / else
if (score >= 90) {
grade = 'A';
} else if (score >= 80) {
grade = 'B';
} else {
grade = 'F';
}
// Ternary
const label = isAdmin ? 'Admin' : 'User';
// Nullish coalescing
const port = process.env.PORT ?? 3000;
// Logical OR fallback (careful: 0 and '' are falsy)
const name = userInput || 'Anonymous';
// Optional chaining
const city = user?.address?.city; // undefined if any is null/undefined
const fn = obj.method?.(); // call only if method exists
// switch
switch (day) {
case 'Mon':
case 'Tue':
console.log('Weekday');
break;
case 'Sat':
case 'Sun':
console.log('Weekend');
break;
default:
console.log('Unknown');
}
Loops
// for
for (let i = 0; i < 5; i++) { }
// for...of (iterables: arrays, strings, Maps, Sets)
for (const item of items) { }
// for...in (object keys — prefer Object.keys())
for (const key in obj) {
if (Object.hasOwn(obj, key)) { } // skip prototype keys
}
// while
while (condition) { }
// do...while (runs at least once)
do { } while (condition);
// Loop control
break; // exit loop
continue; // skip to next iteration
// Array iteration methods (preferred over loops)
arr.forEach((item, index) => { });
arr.map(item => item * 2);
arr.filter(item => item > 0);
arr.reduce((acc, item) => acc + item, 0);
arr.every(item => item > 0); // all match?
arr.some(item => item > 0); // any match?
Functions
// Function declaration (hoisted)
function greet(name) {
return `Hello, ${name}!`;
}
// Function expression
const greet = function(name) {
return `Hello, ${name}!`;
};
// Arrow function
const greet = (name) => `Hello, ${name}!`;
// Arrow function with body
const add = (a, b) => {
const sum = a + b;
return sum;
};
// Default parameters
function createUser(name, role = 'user', active = true) {
return { name, role, active };
}
// Rest parameters
function sum(...nums) {
return nums.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3, 4); // 10
// Destructured parameters
function display({ name, age = 0 }) {
console.log(`${name} (${age})`);
}
// Immediately Invoked Function Expression (IIFE)
(function() {
// private scope
})();
Closures
function makeCounter(start = 0) {
let count = start;
return {
increment() { count++; },
decrement() { count--; },
value() { return count; },
};
}
const counter = makeCounter(10);
counter.increment();
counter.value(); // 11
Higher-order functions
// Function that returns a function
const multiply = (factor) => (n) => n * factor;
const double = multiply(2);
double(5); // 10
// Function that accepts a function
function pipe(...fns) {
return (x) => fns.reduce((v, f) => f(v), x);
}
const transform = pipe(
(s) => s.trim(),
(s) => s.toLowerCase(),
(s) => s.replace(/ /g, '-'),
);
transform(' Hello World '); // 'hello-world'
Arrays
// Create
const arr = [1, 2, 3];
const filled = new Array(5).fill(0); // [0,0,0,0,0]
const range = Array.from({ length: 5 }, (_, i) => i + 1); // [1,2,3,4,5]
const fromStr = Array.from('hello'); // ['h','e','l','l','o']
// Read
arr[0] // 1
arr.at(-1) // 3 — last element
arr.length // 3
// Mutating methods (change the original array)
arr.push(4) // add to end, returns new length
arr.pop() // remove from end, returns element
arr.unshift(0) // add to start, returns new length
arr.shift() // remove from start, returns element
arr.splice(1, 2) // remove 2 elements at index 1
arr.splice(1, 0, 'a') // insert 'a' at index 1
arr.sort() // sort in-place (alphabetical by default)
arr.sort((a, b) => a - b) // sort numerically ascending
arr.reverse() // reverse in-place
arr.fill(0, 1, 3) // fill indices 1-2 with 0
// Non-mutating methods (return new array/value)
arr.slice(1, 3) // ['b','c'] — copy subarray
arr.concat([4, 5]) // merge arrays
arr.join(' - ') // 'a - b - c'
arr.indexOf(2) // first index of 2 (or -1)
arr.lastIndexOf(2) // last index
arr.includes(2) // true/false
arr.find(x => x > 2) // first match
arr.findIndex(x => x > 2) // index of first match
arr.findLast(x => x > 2) // last match (ES2023)
arr.map(x => x * 2) // transform each
arr.filter(x => x % 2 === 0) // keep evens
arr.reduce((acc, x) => acc + x, 0) // sum
arr.flat() // flatten one level
arr.flat(Infinity) // flatten all levels
arr.flatMap(x => [x, x * 2]) // map then flatten one level
arr.every(x => x > 0) // all positive?
arr.some(x => x > 0) // any positive?
// ES2023 non-mutating alternatives
arr.toSorted((a, b) => a - b) // sorted copy
arr.toReversed() // reversed copy
arr.toSpliced(1, 1, 'x') // spliced copy
arr.with(0, 99) // copy with index replaced
// Spread and destructuring
const copy = [...arr];
const merged = [...arr1, ...arr2];
const [first, second, ...rest] = arr;
Objects
// Object literal
const user = {
name: 'Alice',
age: 30,
greet() { // shorthand method
return `Hi, ${this.name}`;
},
};
// Access and modify
user.name // 'Alice'
user['age'] // 30 — bracket notation for dynamic keys
user.email = 'a@b.c' // add property
delete user.age // remove property
// Computed keys
const key = 'status';
const obj = { [key]: 'active' }; // { status: 'active' }
// Shorthand property names
const name = 'Alice';
const age = 30;
const person = { name, age }; // { name: 'Alice', age: 30 }
// Spread and merge
const defaults = { theme: 'dark', lang: 'en' };
const settings = { ...defaults, lang: 'fr' }; // { theme: 'dark', lang: 'fr' }
// Destructuring
const { name, age, email = 'none' } = user; // with default
const { name: userName } = user; // rename
// Nested destructuring
const { address: { city } } = user;
// Object methods
Object.keys(obj) // array of keys
Object.values(obj) // array of values
Object.entries(obj) // array of [key, value] pairs
Object.assign({}, a, b) // shallow merge (mutates first arg)
Object.freeze(obj) // make immutable (shallow)
Object.fromEntries(entries) // convert entries back to object
Object.hasOwn(obj, key) // safer than hasOwnProperty
// Convert entries
const map = new Map([['a', 1], ['b', 2]]);
Object.fromEntries(map) // { a: 1, b: 2 }
const filtered = Object.fromEntries(
Object.entries(obj).filter(([, v]) => v !== null)
);
Classes
class Animal {
#name; // private field (ES2022)
constructor(name, sound) {
this.#name = name;
this.sound = sound;
}
// Getter
get name() { return this.#name; }
// Instance method
speak() {
return `${this.#name} says ${this.sound}`;
}
// Static method
static create(name, sound) {
return new Animal(name, sound);
}
}
class Dog extends Animal {
#tricks = [];
constructor(name) {
super(name, 'woof');
}
learn(trick) {
this.#tricks.push(trick);
return this; // for chaining
}
perform() {
return this.#tricks.join(', ');
}
}
const dog = new Dog('Rex');
dog.learn('sit').learn('shake'); // method chaining
dog.speak(); // 'Rex says woof'
dog instanceof Animal // true
Destructuring and spread (advanced)
// Function parameter defaults with destructuring
function connect({
host = 'localhost',
port = 5432,
ssl = false,
} = {}) { // default empty object so calling with no args works
return `${ssl ? 'ssl://' : ''}${host}:${port}`;
}
// Swap variables
let a = 1, b = 2;
[a, b] = [b, a];
// Skip elements
const [,, third] = [1, 2, 3]; // 3
// Nested array destructuring
const [[x1, y1], [x2, y2]] = [[0, 0], [10, 10]];
// Mix spread with destructuring
function merge(target, ...sources) {
return Object.assign(target, ...sources);
}
Async JavaScript
Promises
// Create a promise
const delay = (ms) =>
new Promise((resolve) => setTimeout(resolve, ms));
// Chain
fetch('/api/users')
.then((res) => res.json())
.then((data) => console.log(data))
.catch((err) => console.error(err))
.finally(() => console.log('done'));
// Promise combinators
Promise.all([p1, p2, p3]) // resolves when all resolve; rejects on first rejection
Promise.allSettled([p1, p2, p3]) // resolves when all settle (success or fail)
Promise.race([p1, p2]) // resolves/rejects with the first to settle
Promise.any([p1, p2, p3]) // resolves with first success; rejects if all fail
async / await
async function fetchUser(id) {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (err) {
console.error('Fetch failed:', err);
throw err;
}
}
// Parallel execution
async function loadAll() {
const [users, posts] = await Promise.all([
fetchUser(1),
fetchPosts(),
]);
return { users, posts };
}
// Sequential (each awaits the previous)
async function processSequential(ids) {
const results = [];
for (const id of ids) {
results.push(await fetchUser(id)); // sequential
}
return results;
}
// Parallel with concurrency limit
async function batchFetch(ids, concurrency = 3) {
const results = [];
for (let i = 0; i < ids.length; i += concurrency) {
const batch = ids.slice(i, i + concurrency);
results.push(...await Promise.all(batch.map(fetchUser)));
}
return results;
}
Error handling
// try / catch / finally
try {
const data = JSON.parse(rawInput);
process(data);
} catch (err) {
if (err instanceof SyntaxError) {
console.error('Invalid JSON:', err.message);
} else {
throw err; // re-throw unexpected errors
}
} finally {
cleanup(); // always runs
}
// Custom error classes
class AppError extends Error {
constructor(message, code) {
super(message);
this.name = 'AppError';
this.code = code;
}
}
class NotFoundError extends AppError {
constructor(resource) {
super(`${resource} not found`, 404);
this.name = 'NotFoundError';
}
}
// Usage
try {
throw new NotFoundError('User');
} catch (err) {
if (err instanceof NotFoundError) {
console.log(err.code); // 404
}
}
Modules (ES Modules)
// math.js — named exports
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export function subtract(a, b) { return a - b; }
// Default export
export default class Calculator { }
// Re-export
export { add, subtract } from './math.js';
export * from './utils.js';
// ---
// Import named
import { add, subtract } from './math.js';
// Import default
import Calculator from './math.js';
// Import both
import Calculator, { PI, add } from './math.js';
// Import all as namespace
import * as math from './math.js';
math.add(1, 2);
// Dynamic import (lazy loading)
const { default: heavy } = await import('./heavy-module.js');
// import.meta (ESM only)
import.meta.url // current module URL
import.meta.env // Vite/build tool env vars
Collections: Map and Set
// Map — ordered key-value with any key type
const map = new Map();
map.set('key', 'value');
map.set(42, 'number key');
map.set({ id: 1 }, 'object key');
map.get('key'); // 'value'
map.has('key'); // true
map.size; // 3
map.delete('key');
map.clear();
// Iterate
for (const [key, value] of map) { }
map.forEach((value, key) => { });
[...map.keys()] // array of keys
[...map.values()] // array of values
[...map.entries()] // array of [key, value]
// Object → Map → Object
const obj = { a: 1, b: 2 };
const m = new Map(Object.entries(obj));
const back = Object.fromEntries(m);
// Set — unique values
const set = new Set([1, 2, 3, 2, 1]); // {1, 2, 3}
set.add(4);
set.has(2); // true
set.size; // 4
set.delete(2);
[...set] // [1, 3, 4]
// Deduplicate an array
const unique = [...new Set(arr)];
// Set operations
const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);
const union = new Set([...a, ...b]); // {1,2,3,4}
const intersection = new Set([...a].filter(x => b.has(x))); // {2,3}
const difference = new Set([...a].filter(x => !b.has(x))); // {1}
Common patterns
Safe JSON parse
function safeParseJSON(str, fallback = null) {
try {
return JSON.parse(str);
} catch {
return fallback;
}
}
Deep clone
// Simple (no functions, dates, or circular refs)
const clone = JSON.parse(JSON.stringify(obj));
// Modern (handles Dates, RegExp, typed arrays, Maps, Sets)
const clone = structuredClone(obj);
Debounce
function debounce(fn, wait) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), wait);
};
}
const search = debounce((q) => fetchResults(q), 300);
Throttle
function throttle(fn, limit) {
let lastCall = 0;
return (...args) => {
const now = Date.now();
if (now - lastCall >= limit) {
lastCall = now;
return fn(...args);
}
};
}
Memoize
function memoize(fn) {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}
Group array by key
// ES2024 Object.groupBy
const grouped = Object.groupBy(people, ({ age }) =>
age >= 18 ? 'adults' : 'minors'
);
// Fallback (older environments)
const grouped = people.reduce((acc, person) => {
const key = person.age >= 18 ? 'adults' : 'minors';
(acc[key] ??= []).push(person);
return acc;
}, {});
Flatten nested array
const nested = [1, [2, [3, [4]]]];
nested.flat() // [1, 2, [3, [4]]]
nested.flat(Infinity) // [1, 2, 3, 4]
Common mistakes
| Mistake | Why it fails | Fix |
|---|---|---|
arr.forEach with async |
forEach ignores returned promises |
Use for...of or Promise.all(arr.map(...)) |
0 == false |
Loose equality coerces types | Always use === |
Mutating state in map/filter |
Side effects break predictability | Keep callbacks pure; use reduce for accumulation |
const obj = {}; obj.key = v |
const prevents reassignment, not mutation |
Use Object.freeze if immutability is needed |
typeof null === 'object' |
Historical JS bug | Use x === null to check for null |
var in loops |
Shared binding across iterations | Use let |
| Not handling rejected promises | Unhandled rejections crash Node.js | Always .catch() or try/catch |
arr.sort() sorts lexicographically |
[10,2,1].sort() → [1,10,2] |
Pass comparator: arr.sort((a,b) => a-b) |
JavaScript vs TypeScript quick reference
| Feature | JavaScript | TypeScript |
|---|---|---|
| Type annotations | No | let x: number |
| Interfaces | No | interface Foo { x: number } |
| Generics | No | function id<T>(x: T): T |
| Enums | No | enum Color { Red, Green } |
| Compile step | No | tsc or bundler |
| Runtime errors from types | Yes | Caught at compile time |
any type |
N/A | Opt-in escape hatch |
FAQ
What is the difference between == and ===?
=== checks value and type (no coercion). == coerces types before comparing. Use === always unless you explicitly want type coercion (rare).
What is the difference between null and undefined?
undefined means a variable was declared but not assigned, or a property doesn't exist. null is an intentional "no value." Both are falsy; use ?? (nullish coalescing) to handle both: x ?? 'default'.
How do I copy an object without mutating the original?
Shallow: { ...obj } or Object.assign({}, obj). Deep (handles nested): structuredClone(obj) (modern environments) or JSON.parse(JSON.stringify(obj)) (no Date/Function/circular).
When should I use Map instead of a plain object?
Use Map when: keys aren't strings (e.g., object keys), you need insertion-order iteration guaranteed, you frequently add/delete keys, or you need .size. Use objects for simple static data and when interacting with JSON.
What is the event loop?
JavaScript is single-threaded. The event loop processes the call stack first, then microtasks (Promises, queueMicrotask), then macrotasks (setTimeout, setInterval, I/O). await yields to the event loop, allowing other microtasks to run.
What is hoisting?
Variable declarations with var and function declarations are moved to the top of their scope before execution. let and const are hoisted but not initialized — accessing them before declaration throws a ReferenceError (the "temporal dead zone").