⚡ JavaScript

← Back to Cheatsheets

A quick-reference for the most commonly used JavaScript features. JavaScript is a dynamically typed, JIT-compiled language that runs in browsers and on servers (Node.js). Functions are first-class values, prototype-based inheritance underpins OOP, and the event loop drives asynchronous execution.

Paradigm: Multi-paradigm (OOP via prototypes, Functional, Event-driven) Typing: Dynamic · Weak (implicit coercion) Execution: JIT-compiled · Garbage collected
Resources: MDN JavaScript docs javascript.info ECMAScript spec Node.js docs caniuse.com

Variables & Types

▼

Prefer const by default; use let only when the binding will be reassigned. Avoid var — it is function-scoped and hoisted. JavaScript has seven primitive types; everything else is an object.

Declarations
const x = 42;          // block-scoped, cannot be reassigned
let count = 0;         // block-scoped, can be reassigned
var legacy = true;     // function-scoped, hoisted — avoid
Primitive types
typeof "hello"     // "string"
typeof 42          // "number"
typeof 42n         // "bigint"
typeof true        // "boolean"
typeof undefined   // "undefined"
typeof null        // "object"  ← historical bug, null IS primitive
typeof Symbol()    // "symbol"
use === null to check for null; typeof null is misleading
Equality — always use ===
0 == "0"   // true  (coercion)
0 === "0"  // false (no coercion)
== triggers implicit type coercion; === checks type and value
Nullish coalescing & optional chaining
const val = input ?? "default";
const city = user?.address?.city;
?? returns right side only for null/undefined, unlike || which triggers on 0, "", false

Built-in Functions

▼

JavaScript global functions and methods available without any import. These cover type checking, conversion, math, and JSON serialisation.

Type checking & conversion
typeof value          // "string" | "number" | "boolean" | ...
Array.isArray(x)      // true only for arrays (typeof returns "object")
Number("42")          // 42  (NaN if invalid)
String(42)            // "42"
Boolean(0)            // false
parseInt("42px", 10)  // 42  (always pass radix)
parseFloat("3.14")    // 3.14
prefer Number() over parseInt() for strict numeric conversion
Console
console.log("info", value)
console.warn("warning")
console.error("error", err)
console.table([{a: 1}, {a: 2}])  // tabular output
console.time("label")
console.timeEnd("label")          // elapsed ms
Math
Math.min(1, 2, 3)   // 1
Math.max(1, 2, 3)   // 3
Math.floor(3.9)     // 3
Math.ceil(3.1)      // 4
Math.round(3.5)     // 4
Math.abs(-5)        // 5
Math.random()       // [0, 1)
JSON
JSON.stringify(obj)             // → string
JSON.stringify(obj, null, 2)    // → pretty-printed
JSON.parse(str)                 // → object (throws on invalid JSON)

// safe parse pattern
try {
    const data = JSON.parse(raw);
} catch (e) { /* handle */ }
JSON.stringify ignores functions and undefined values; use replacer for custom behaviour

Loops & Control Flow

▼

JavaScript supports classic C-style for, for...of for iterables, for...in for object keys, and while/do...while. Prefer for...of over forEach when you need break/continue.

For loops
for (let i = 0; i < arr.length; i++) {}     // classic, index-based
for (const item of arr) {}                   // iterate values (arrays, strings, Maps, Sets)
for (const [k, v] of Object.entries(obj)) {} // iterate object key-value pairs
for (const key in obj) {}                    // iterate own + inherited keys (usually avoid)
for...of works on any iterable; for...in is for object keys (avoid for arrays)
While / do-while
while (condition) { }

do {
    // runs at least once
} while (condition);
If / ternary / switch
if (x > 0) { } else if (x < 0) { } else { }

const label = x > 0 ? "positive" : "non-positive";

switch (status) {
    case "ok":   break;
    case "fail": break;
    default:     break;
}
switch uses === comparison; always include break or return in each case
Break / continue / labeled
outer: for (const row of matrix) {
    for (const cell of row) {
        if (cell === 0) break outer;    // exits both loops
        if (cell < 0)  continue outer; // next row
    }
}
labels are rarely needed — restructure with functions when possible

String Manipulation

▼

Strings are immutable — all methods return new strings. Template literals support embedded expressions and multi-line strings.

Template literal
const msg = `Hello ${name}, you have ${count} messages`;
supports any expression inside ${}; can span multiple lines
Search
s.includes("sub")
s.startsWith("pre")
s.endsWith("suf")
s.indexOf("x")    // -1 if not found
Transform
s.toLowerCase()
s.toUpperCase()
s.trim()
s.trimStart()
s.trimEnd()
s.replace("old", "new")
s.replaceAll("old", "new")
Split & slice
s.split(",")          // array of parts
arr.join(", ")        // join array into string
s.slice(start, end)   // negative indices count from end
s.padStart(10, "0")   // pad to length
s.repeat(3)           // repeat n times

Collections

▼

Sequence → Array, Map → Object or Map, Set → Set. Arrays are objects with numeric keys. Map and Set are purpose-built and preserve insertion order.

Sequence (Array) — transform
arr.map(x => x * 2)               // new array, same length
arr.filter(x => x > 0)            // new array, subset
arr.reduce((acc, x) => acc + x, 0) // fold to single value
arr.flatMap(x => [x, x * 2])      // map then flatten one level
Sequence (Array) — search & test
arr.find(x => x > 5)      // first match or undefined
arr.findIndex(x => x > 5) // index or -1
arr.some(x => x > 5)      // true if any match
arr.every(x => x > 0)     // true if all match
arr.includes(value)        // membership test
Sequence (Array) — mutate
arr.push(x)          // append — returns new length
arr.pop()            // remove last — returns element
arr.unshift(x)       // prepend
arr.shift()          // remove first
arr.splice(i, n)     // remove n elements at index i
arr.sort((a, b) => a - b)  // in-place sort; always pass comparator
.sort() without a comparator converts to strings — leads to bugs with numbers
Map (Object) — access & iteration
obj.key / obj["key"]             // get
obj.key = value                  // set
delete obj.key                   // remove
"key" in obj                     // membership test
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
Map and Set
const m = new Map();
m.set("key", value);
m.get("key");
m.has("key");

const s = new Set([1, 2, 3]);
s.add(4);
s.has(2);    // true
[...s]       // convert to array
Map allows any key type and preserves insertion order

Data Type Interaction Matrix

Interaction Array Object Map Set String
Access item arr[i] / arr.at(i) obj[k] / obj.k map.get(k) Unindexed str[i] / str.at(i)
Access last item arr.at(-1) / arr[arr.length - 1] Object.values(obj).at(-1) [...map.values()].at(-1) [...set].at(-1) str.at(-1) / str[str.length - 1]
Add / Append arr.push(x) obj[k] = v map.set(k, v) set.add(x) str += "x"
Insert at index arr.splice(i, 0, x) N/A (by key) N/A (by key) N/A (unordered) str.slice(0, i) + "x" + str.slice(i)
Update item arr[i] = val obj[k] = val map.set(k, val) set.delete(o); set.add(n) str.replace(o, n)
Update last item arr[arr.length - 1] = val N/A N/A N/A str.slice(0, -1) + "c"
Remove item arr.splice(i, 1) delete obj[k] map.delete(k) set.delete(x) str.replace(sub, "")
Pop (remove & get) arr.pop() (last) v = obj[k]; delete obj[k] v = map.get(k); map.delete(k) v = set.values().next().value; set.delete(v) last = str.at(-1); str = str.slice(0, -1)
Check existence arr.includes(x) (O(n)) k in obj / obj.hasOwnProperty(k) (O(1)) map.has(k) (O(1)) set.has(x) (O(1)) str.includes(sub)
Clear / Empty arr.length = 0 for (let k in obj) delete obj[k] map.clear() set.clear() str = ""
Mutable in-place? Yes Yes Yes Yes No (Immutable)
Ordered? Yes (0-indexed) Yes (String key order) Yes (Insertion) Yes (Insertion) Yes (0-indexed)

Functions

▼

Functions are first-class values. Arrow functions inherit this from the surrounding scope — regular functions bind their own this. Use arrow functions for callbacks.

Declaration forms
function greet(name) { return `Hi ${name}`; }  // hoisted
const greet = function(name) { ... };           // expression
const greet = (name) => `Hi ${name}`;          // arrow (implicit return)
const greet = (name) => { return `Hi ${name}`; }; // arrow (explicit)
Default & rest parameters
function greet(name = "World") {
    return `Hi ${name}`;
}

function sum(...nums) {
    return nums.reduce((a, b) => a + b, 0);
}
Spread
const merged = [...arr1, ...arr2];
const copy = { ...obj, extra: true };
Math.max(...arr);
Closures
function counter() {
    let count = 0;
    return () => ++count;
}
const inc = counter();
inc(); // 1
inc(); // 2
inner function retains a reference to count; each counter() call gets its own count

Async & Promises

▼

JavaScript is single-threaded. async/await is syntactic sugar over Promises — an async function always returns a Promise. Use await only inside async functions.

async/await — fetch example
async function getUser(id) {
    const res = await fetch(`/api/users/${id}`);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return res.json();
}

// call it
const user = await getUser(42);        // inside async context
getUser(42).then(u => console.log(u)); // outside async context
Promise combinators
// all must succeed — rejects on first failure
const [a, b] = await Promise.all([fetchA(), fetchB()]);

// wait for all regardless of failures
const results = await Promise.allSettled([fetchA(), fetchB()]);

// first to settle wins
const fastest = await Promise.race([fetchA(), fetchB()]);
Promise chain
fetch("/api/data")
    .then(res => res.json())
    .then(data => console.log(data))
    .catch(err => console.error(err))
    .finally(() => setLoading(false));

Error Handling

▼

Wrap unpredictable operations in try/catch. finally runs regardless of success or failure — use it for cleanup.

try / catch / finally
try {
    const data = JSON.parse(raw);
} catch (err) {
    if (err instanceof SyntaxError) {
        console.error("Invalid JSON:", err.message);
    } else {
        throw err;   // re-throw unexpected errors
    }
} finally {
    cleanup();
}
Custom error
class NotFoundError extends Error {
    constructor(resource) {
        super(`${resource} not found`);
        this.name = "NotFoundError";
    }
}
throw new NotFoundError("User 42");
Async error handling
try {
    await riskyFn();
} catch (err) {
    // handle error
}
await throws on rejected promises — wrap in try/catch

Common Patterns

▼

Modern JavaScript idioms that appear in almost every codebase.

Destructuring
const { name, age = 0 } = user;          // object, with default
const { name: userName } = user;          // rename on extract
const [first, , third] = arr;            // array, skip element
const { a, ...rest } = obj;              // rest in object destructure
Modules (ES modules)
// named exports
export const PI = 3.14;
export function add(a, b) { return a + b; }

// default export
export default class App { ... }

// import
import App, { PI, add } from "./math.js";
import * as math from "./math.js";
Short-circuit & conditional
const val = a ?? b;            // b only if a is null/undefined
const val = a || b;            // b if a is falsy (0, "", false, null)
const val = a && b;            // b only if a is truthy
condition && doSomething();    // guard — execute only if condition is true
const x = flag ? "yes" : "no"; // ternary
Iteration patterns
for (const item of arr) { }                        // iterable (arrays, strings, maps, sets)
for (const [k, v] of Object.entries(obj)) { }      // object iteration
arr.forEach((item, i) => { });                     // side effects with index