DEV Community

Cover image for JavaScript Cheat Sheet 2026: Learn Once, Remember Forever (ES2026)
VIKAS
VIKAS

Posted on

JavaScript Cheat Sheet 2026: Learn Once, Remember Forever (ES2026)

Most JavaScript tutorials are long. Most cheat sheets stop at ES6. This one does neither.

It is written against ECMAScript 2026 (the 17th edition of the spec, June 2026) and MDN, and it works for three kinds of people:

  • Beginners and intermediates: read it top to bottom like a crash course.
  • Job seekers: jump to Interview Rapid Fire and Predict the Output.
  • Working devs: use the table of contents as a quick revision index.

Every concept follows one pattern: what it is, the smallest useful example, and the trap to avoid.


Table of Contents

  1. How JavaScript runs
  2. Variables, scope and hoisting
  3. Data types
  4. Coercion and equality
  5. Operators worth knowing
  6. Strings, numbers and Math
  7. Control flow and loops
  8. Functions and this
  9. Closures
  10. Objects
  11. Arrays
  12. Map, Set, WeakMap, WeakSet
  13. Prototypes and classes
  14. Modules
  15. Asynchronous JavaScript
  16. Error handling
  17. Iterators and generators
  18. JSON, dates and Intl
  19. Regular expressions
  20. Browser essentials (DOM and Web APIs)
  21. Performance and memory
  22. Security basics
  23. ES2015 to ES2026 at a glance
  24. Gotchas that bite everyone
  25. Predict the Output
  26. Interview Rapid Fire
  27. Official resources

1. How JavaScript runs

  • JavaScript is single-threaded: one call stack, one thing at a time.
  • It is interpreted/JIT-compiled by an engine (V8 in Chrome, Node.js, Deno and Bun; SpiderMonkey in Firefox; JavaScriptCore in Safari).
  • It is dynamically typed: variables have no type, values do.
  • ECMAScript is the language spec. Web APIs (fetch, DOM, setTimeout) are provided by the host (browser or Node), not by the language itself.
Runs in Notes
Browser DOM, window, fetch, storage
Node.js / Deno / Bun Files, network, processes, no DOM
Edge runtimes Cloudflare Workers, Vercel Edge (Web APIs, limited Node APIs)
console.log('Hello, JS');   // run in browser DevTools console, or: node file.js
Enter fullscreen mode Exit fullscreen mode

Strict mode ('use strict') turns silent mistakes into errors. ES modules and classes are strict by default, so you rarely need the directive today.


2. Variables, scope and hoisting

var let const
Scope Function Block Block
Reassign Yes Yes No
Redeclare Yes No No
Hoisted Yes, initialized as undefined Yes, but in the Temporal Dead Zone Yes, but in the TDZ
const PI = 3.14159;       // default choice
let count = 0;            // when you need to reassign
// avoid var

const user = { name: 'A' };
user.name = 'B';          // allowed: const protects the binding, not the contents
// user = {};             // TypeError
Enter fullscreen mode Exit fullscreen mode

Scope types: global, function, block ({} with let/const), module.

Hoisting:

console.log(a);   // undefined (var is hoisted)
var a = 5;

console.log(b);   // ReferenceError (TDZ)
let b = 5;

sayHi();          // works: function declarations are fully hoisted
function sayHi() { console.log('hi'); }

hello();          // TypeError: hello is not a function (var hoisted, value not yet assigned)
var hello = () => {};
Enter fullscreen mode Exit fullscreen mode

Rule of thumb: const by default, let when needed, never var.


3. Data types

7 primitives (immutable, copied by value): string, number, bigint, boolean, undefined, null, symbol.
Everything else is an object (copied by reference): objects, arrays, functions, dates, maps, sets.

Expression typeof result
'hi' 'string'
42, NaN, Infinity 'number'
10n 'bigint'
true 'boolean'
undefined 'undefined'
null 'object' (historic bug)
Symbol() 'symbol'
[], {} 'object' (use Array.isArray)
() => {} 'function'
Array.isArray([]);          // true
value === null;             // the right null check
value == null;              // true for both null and undefined (the one accepted use of ==)
Enter fullscreen mode Exit fullscreen mode

Value vs reference

let a = 1; let b = a; b = 2;       // a is still 1 (copied)

const o1 = { x: 1 };
const o2 = o1;                     // same object
o2.x = 99;                         // o1.x is now 99
Enter fullscreen mode Exit fullscreen mode

Copying objects

Method Depth Notes
{ ...obj }, Object.assign({}, obj) Shallow Nested objects are still shared
structuredClone(obj) Deep Handles Date, Map, Set, circular refs. Fails on functions and DOM nodes.
JSON.parse(JSON.stringify(obj)) Deep, lossy Drops undefined, functions, turns Dates into strings. Avoid.

Number gotchas

0.1 + 0.2 === 0.3;                          // false (0.30000000000000004)
Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON; // true: compare floats like this
Number.MAX_SAFE_INTEGER;                    // 9007199254740991, beyond this use BigInt
NaN === NaN;                                // false
Number.isNaN(NaN);                          // true (use this, not isNaN())
9007199254740993n + 1n;                     // BigInt: arbitrary precision, no mixing with Number
Enter fullscreen mode Exit fullscreen mode

4. Coercion and equality

Use === always. The only common exception: x == null to check null or undefined.

== converts types first. === does not.

1 == '1';           // true
1 === '1';          // false
null == undefined;  // true
null === undefined; // false
Object.is(NaN, NaN);// true (like === but NaN equals NaN, and +0 differs from -0)
Enter fullscreen mode Exit fullscreen mode

Falsy values (there are exactly 8)

false, 0, -0, 0n, '', null, undefined, NaN

Everything else is truthy, including '0', 'false', [], {}.

Classic coercion results

1 + '2';        // '12'  (+ prefers strings)
'3' - 1;        // 2     (- forces numbers)
'5' * '2';      // 10
[] + [];        // ''
[] + {};        // '[object Object]'
true + 1;       // 2
Number('');     // 0
Number('12px'); // NaN
parseInt('12px', 10); // 12 (always pass the radix)
Enter fullscreen mode Exit fullscreen mode

Convert explicitly: Number(x), String(x), Boolean(x) or !!x, parseInt(x, 10), parseFloat(x).


5. Operators worth knowing

Operator Meaning Example
?. Optional chaining user?.address?.city, fn?.(), arr?.[0]
?? Nullish coalescing (only null or undefined) count ?? 10
`\ \ `
??= `\ \ = &&=`
** Exponent 2 ** 10 is 1024
... Spread (expand) or rest (collect) [...a, ...b], (...args) =>
? : Ternary ok ? 'yes' : 'no'
typeof, instanceof, in Type checks 'a' in obj
1_000_000 Numeric separator readability only
const port = config.port ?? 3000;     // keeps 0 if port is 0
const port2 = config.port || 3000;    // replaces 0 with 3000 (bug)
const city = user?.address?.city;     // undefined instead of TypeError
Enter fullscreen mode Exit fullscreen mode

6. Strings, numbers and Math

Strings (immutable)

const name = 'World';
`Hello, ${name}! ${2 + 3}`;     // template literal, multi-line allowed
Enter fullscreen mode Exit fullscreen mode
Method Does
slice(start, end) Substring (negative indexes allowed)
at(-1) Last character
includes, startsWith, endsWith Boolean checks
indexOf(x) Position or -1
split(',') and arr.join(',') String to array and back
trim(), trimStart(), trimEnd() Remove whitespace
padStart(5, '0'), padEnd() '7'.padStart(3,'0') gives '007'
replace(a, b), replaceAll(a, b) replace with a string only changes the first match
toUpperCase(), toLowerCase() Case
repeat(3) 'ab'.repeat(2) gives 'abab'
localeCompare(b) Correct sorting for human languages
isWellFormed(), toWellFormed() Check or fix lone surrogates

'😀'.length is 2. Length counts UTF-16 units. Use [...str].length to count characters (code points).

Numbers and Math

(1234.5678).toFixed(2);          // '1234.57' (returns a STRING)
Number.isInteger(5);             // true
Math.round(2.5);                 // 3
Math.floor(-1.5);                // -2
Math.trunc(-1.5);                // -1
Math.max(...nums);               // Math.max() with no args is -Infinity
Math.floor(Math.random() * (max - min + 1)) + min;   // random int in [min, max]
Enter fullscreen mode Exit fullscreen mode

Math.sumPrecise(list) (ES2026) adds many numbers without accumulating rounding error.


7. Control flow and loops

if (x > 0) { } else if (x === 0) { } else { }

switch (day) {
  case 'sat':
  case 'sun': console.log('weekend'); break;   // forget break and it falls through
  default: console.log('weekday');
}
Enter fullscreen mode Exit fullscreen mode
Loop Use for
for (let i = 0; i < n; i++) Counted loops
for (const x of iterable) Values of arrays, strings, Maps, Sets, generators. Default choice.
for (const key in obj) Enumerable keys of an object (also inherited ones). Avoid on arrays.
while, do...while Unknown number of iterations
arr.forEach(fn) Side effects. Cannot break, does not wait for await.
for await (const x of asyncIterable) Async streams
for (const [i, value] of arr.entries()) { }
for (const [key, value] of Object.entries(obj)) { }
for (const [key, value] of map) { }

outer: for (const a of A) {           // label to break out of nested loops
  for (const b of B) { if (a === b) break outer; }
}
Enter fullscreen mode Exit fullscreen mode

8. Functions and this

Ways to write a function

function add(a, b) { return a + b; }            // declaration (hoisted)
const sub = function (a, b) { return a - b; };  // expression
const mul = (a, b) => a * b;                    // arrow, implicit return
const makeUser = name => ({ name });            // wrap returned object literal in ()
Enter fullscreen mode Exit fullscreen mode

Parameters

function greet(name = 'friend', ...rest) {      // default value, rest parameter
  return `Hi ${name} (+${rest.length} extra)`;
}
const [first, second] = [1, 2];                 // destructuring
function area({ w, h = 1 }) { return w * h; }   // destructure a param object
Enter fullscreen mode Exit fullscreen mode

Arrow functions vs regular functions

Regular Arrow
Own this Yes, depends on the call No, uses surrounding this
arguments Yes No (use ...rest)
Can use new Yes No
Good as object method Yes No
Good as callback Sure Best

What is this? (4 rules, in priority order)

  1. new Fn(): this is the new object.
  2. fn.call(obj), apply, bind: this is obj.
  3. obj.method(): this is obj.
  4. Plain fn(): this is undefined in strict mode, globalThis otherwise.

Arrow functions skip all of this and inherit this from where they were written.

const user = {
  name: 'Asha',
  hi() { return this.name; },
  later() { setTimeout(() => console.log(this.name), 100); }, // arrow keeps this
};

const f = user.hi;
f();                      // this is lost
f.call(user);             // 'Asha'
const bound = user.hi.bind(user);
bound();                  // 'Asha'
Enter fullscreen mode Exit fullscreen mode
fn.call(obj, a, b);       // call now, args listed
fn.apply(obj, [a, b]);    // call now, args as array
fn.bind(obj, a);          // returns a new function, call later
Enter fullscreen mode Exit fullscreen mode

Handy patterns

(() => { /* IIFE: runs immediately, rarely needed with modules */ })();

const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);   // composition
const curry = a => b => a + b;                                          // currying

function fact(n) { return n <= 1 ? 1 : n * fact(n - 1); }              // recursion needs a base case
Enter fullscreen mode Exit fullscreen mode

Higher-order function: takes or returns a function (map, filter, addEventListener).
Pure function: same input, same output, no side effects. Easiest code to test.


9. Closures

A closure is a function that remembers the variables from where it was created, even after that outer function has finished.

function counter() {
  let n = 0;                // private, nobody else can touch it
  return () => ++n;
}
const next = counter();
next(); // 1
next(); // 2
Enter fullscreen mode Exit fullscreen mode

Used for: private state, factories, memoization, debounce, event handlers, callbacks.

The classic loop bug

for (var i = 0; i < 3; i++) setTimeout(() => console.log(i));   // 3 3 3 (one shared var)
for (let i = 0; i < 3; i++) setTimeout(() => console.log(i));   // 0 1 2 (new let per iteration)
Enter fullscreen mode Exit fullscreen mode

Debounce and throttle

function debounce(fn, ms = 300) {            // run after the user STOPS for ms
  let t;
  return (...args) => {
    clearTimeout(t);
    t = setTimeout(() => fn(...args), ms);
  };
}

function throttle(fn, ms = 300) {            // run at most once per ms
  let last = 0;
  return (...args) => {
    const now = Date.now();
    if (now - last >= ms) { last = now; fn(...args); }
  };
}
Enter fullscreen mode Exit fullscreen mode

Closures can keep big objects alive. Clear timers and listeners you no longer need.


10. Objects

const name = 'Asha';
const user = {
  name,                              // shorthand for name: name
  age: 30,
  ['is' + 'Admin']: false,           // computed key
  greet() { return `Hi ${this.name}`; },
  get label() { return `${this.name} (${this.age})`; },
};

user.name;  user['name'];            // two ways to read
delete user.age;
'name' in user;                      // true (includes inherited)
Object.hasOwn(user, 'name');         // true (own property, modern replacement for hasOwnProperty)
Enter fullscreen mode Exit fullscreen mode

Destructuring and spread

const { name: userName, age = 18, ...others } = user;      // rename, default, rest
const updated = { ...user, age: 31 };                      // copy + override
const merged = { ...defaults, ...overrides };              // later wins
Enter fullscreen mode Exit fullscreen mode

Essential Object methods

Method Does
Object.keys(o), values(o), entries(o) Arrays of own enumerable keys, values, pairs
Object.fromEntries(pairs) Pairs back to an object
Object.assign(target, ...src) Shallow merge (mutates target)
Object.freeze(o) Shallow immutable (silent fail, or TypeError in strict mode)
Object.groupBy(items, fn) Group an array into an object by key (ES2024)
Object.create(proto) New object with a chosen prototype
Object.defineProperty(o, k, desc) Control writable, enumerable, configurable
Object.getPrototypeOf(o) Read the prototype
const prices = { a: 10, b: 20 };
Object.fromEntries(Object.entries(prices).map(([k, v]) => [k, v * 2]));  // { a: 20, b: 40 }

Object.groupBy([1, 2, 3, 4], n => (n % 2 ? 'odd' : 'even'));  // { odd: [1,3], even: [2,4] }
Enter fullscreen mode Exit fullscreen mode

Key order: integer-like keys first (ascending), then strings in insertion order.


11. Arrays

Mutating vs non-mutating (memorize this)

Mutates the original Returns a new array
push, pop, shift, unshift map, filter, slice, concat, flat, flatMap
splice, sort, reverse, fill toSorted, toReversed, toSpliced, with (ES2023)

Everyday methods

const nums = [5, 1, 4];

nums.map(n => n * 2);                    // [10, 2, 8]
nums.filter(n => n > 1);                 // [5, 4]
nums.find(n => n > 1);                   // 5 (first match or undefined)
nums.findLast(n => n > 1);               // 4
nums.some(n => n > 4);                   // true
nums.every(n => n > 0);                  // true
nums.includes(4);                        // true
nums.reduce((sum, n) => sum + n, 0);     // 10 (always give an initial value)
nums.at(-1);                             // 4
nums.slice(1, 3);                        // [1, 4]
nums.flat(Infinity);                     // flatten nested arrays
Array.from({ length: 3 }, (_, i) => i);  // [0, 1, 2]
[...new Set(nums)];                      // unique values
Enter fullscreen mode Exit fullscreen mode

Sorting

[10, 9, 1].sort();                       // [1, 10, 9] (default sorts as STRINGS)
[10, 9, 1].sort((a, b) => a - b);        // [1, 9, 10]
[10, 9, 1].toSorted((a, b) => b - a);    // [10, 9, 1] (original untouched)

people.sort((a, b) => a.name.localeCompare(b.name));   // sort strings properly
Enter fullscreen mode Exit fullscreen mode

Immutable updates

const add    = [...arr, item];
const remove = arr.filter(x => x.id !== id);
const update = arr.map(x => (x.id === id ? { ...x, done: true } : x));
const swap   = arr.with(2, 'new');       // replace index 2
Enter fullscreen mode Exit fullscreen mode

Real-world pipeline

const total = orders
  .filter(o => o.status === 'paid')
  .map(o => o.amount)
  .reduce((sum, n) => sum + n, 0);
Enter fullscreen mode Exit fullscreen mode

arr.length = 0 empties an array. arr[100] = 1 on a short array creates holes. Array(3) is empty slots, not [undefined, undefined, undefined].


12. Map, Set, WeakMap, WeakSet

Map vs plain object

Map Object
Key types Anything Strings and symbols
Order Insertion Insertion (integer keys first)
Size map.size Object.keys(o).length
Frequent add/remove Faster Slower
JSON No direct support Yes
const m = new Map([['a', 1]]);
m.set('b', 2).get('b');          // 2
m.has('a');  m.delete('a');  m.size;
for (const [k, v] of m) { }

// count things (ES2026 getOrInsert, check engine support)
const counts = new Map();
for (const w of words) counts.set(w, counts.getOrInsert(w, 0) + 1);
Enter fullscreen mode Exit fullscreen mode

Set (unique values)

const s = new Set([1, 2, 2, 3]);   // {1, 2, 3}
s.add(4);  s.has(2);  s.delete(1);  s.size;
Enter fullscreen mode Exit fullscreen mode

Set algebra (ES2025):

const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);

a.union(b);                // {1, 2, 3, 4}
a.intersection(b);         // {2, 3}
a.difference(b);           // {1}
a.symmetricDifference(b);  // {1, 4}
a.isSubsetOf(b);  a.isSupersetOf(b);  a.isDisjointFrom(b);
Enter fullscreen mode Exit fullscreen mode

WeakMap and WeakSet

Keys must be objects (or non-registered symbols), held weakly so they can be garbage collected. Not iterable, no size. Use for metadata attached to objects without causing leaks.

const meta = new WeakMap();
meta.set(domNode, { clicks: 0 });    // entry disappears when domNode is collected
Enter fullscreen mode Exit fullscreen mode

13. Prototypes and classes

The prototype chain

Every object has a hidden link to another object (its prototype). Property lookup walks that chain until null.

const animal = { eats: true };
const dog = Object.create(animal);
dog.barks = true;
dog.eats;                                  // true (found on the prototype)
Object.getPrototypeOf(dog) === animal;     // true
Enter fullscreen mode Exit fullscreen mode

class is cleaner syntax over the same prototype system.

Classes

class Account {
  #balance = 0;                          // truly private
  static count = 0;                      // belongs to the class

  constructor(owner) {
    this.owner = owner;
    Account.count++;
  }

  deposit(n) {
    if (n <= 0) throw new RangeError('Amount must be positive');
    this.#balance += n;
    return this;                         // enables chaining
  }

  get balance() { return this.#balance; }
  static create(owner) { return new Account(owner); }
}

class Savings extends Account {
  constructor(owner, rate) {
    super(owner);                        // must call super before using this
    this.rate = rate;
  }
  deposit(n) { return super.deposit(n * 1.01); }
}

const s = new Savings('Asha', 0.05);
s instanceof Account;                    // true
s.balance;                               // 0
// s.#balance                            // SyntaxError (private)
Enter fullscreen mode Exit fullscreen mode

Facts:

  • Methods live on the prototype (shared). Class fields (x = 1) live on each instance.
  • Class bodies are strict mode. Classes are not hoisted like functions (TDZ).
  • #private fields cannot be read from outside, even by subclasses. Check with #x in obj.
  • static { } blocks run once at class definition for setup.
  • Prefer composition over deep inheritance.

14. Modules

ES Modules (ESM) CommonJS (CJS)
Syntax import / export require() / module.exports
Loading Static, async Dynamic, sync
Top-level await Yes No
Default in Browsers, modern Node ("type": "module" or .mjs) Older Node (.cjs)
// math.js
export const PI = 3.14;
export function add(a, b) { return a + b; }
export default class Calculator {}

// app.js
import Calculator, { PI, add as sum } from './math.js';
import * as math from './math.js';

const { default: Chart } = await import('./chart.js');     // dynamic import (lazy load)
import config from './config.json' with { type: 'json' };  // JSON modules (ES2025)
Enter fullscreen mode Exit fullscreen mode
  • Browsers: <script type="module" src="app.js"></script>.
  • ESM imports are live bindings and are hoisted. Modules run once and are cached.
  • Prefer named exports (better refactoring and tree shaking).
  • Always include the file extension in browser and Node ESM imports.

15. Asynchronous JavaScript

The event loop (the one diagram to memorize)

Call Stack  <---  Microtask queue (Promises, queueMicrotask)      runs FIRST, fully drained
            <---  Macrotask queue (setTimeout, events, I/O)       ONE task, then microtasks again
Enter fullscreen mode Exit fullscreen mode

Order: run sync code, drain all microtasks, run one macrotask, drain microtasks, repeat.

console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
queueMicrotask(() => console.log('4'));
console.log('5');
// 1, 5, 3, 4, 2
Enter fullscreen mode Exit fullscreen mode

In Node.js, process.nextTick runs even before Promise microtasks.

Promises

A Promise is a value that arrives later. States: pending, fulfilled, rejected.

fetch('/api/user')
  .then(res => res.json())
  .then(user => console.log(user))
  .catch(err => console.error(err))
  .finally(() => hideSpinner());
Enter fullscreen mode Exit fullscreen mode
Combinator Resolves when Rejects when
Promise.all([...]) All fulfilled (array of results) Any rejects (fail fast)
Promise.allSettled([...]) All settled ({status, value/reason}) Never
Promise.race([...]) First settles First rejection if it is first
Promise.any([...]) First fulfills All reject (AggregateError)
const { promise, resolve, reject } = Promise.withResolvers();   // ES2024
Promise.try(() => maybeSyncOrAsync());   // ES2025: sync throws become rejections, result is always a Promise
Enter fullscreen mode Exit fullscreen mode

async / await

async function loadUser(id) {
  try {
    const res = await fetch(`/api/users/${id}`, { signal: AbortSignal.timeout(5000) });
    if (!res.ok) throw new Error(`HTTP ${res.status}`);   // fetch does NOT reject on 404 or 500
    return await res.json();
  } catch (err) {
    console.error('Load failed', err);
    throw err;
  } finally {
    hideSpinner();
  }
}
Enter fullscreen mode Exit fullscreen mode
  • An async function always returns a Promise.
  • await only pauses that function, not the whole program.

Sequential vs parallel (huge performance difference)

const a = await getA();
const b = await getB();                        // waits for A first (slow)

const [a2, b2] = await Promise.all([getA(), getB()]);   // both start together (fast)
Enter fullscreen mode Exit fullscreen mode

Common async mistakes

items.forEach(async item => { await save(item); });     // forEach does NOT wait
await Promise.all(items.map(item => save(item)));       // correct, parallel
for (const item of items) await save(item);             // correct, one by one
Enter fullscreen mode Exit fullscreen mode

Cancel, timeout, retry

const controller = new AbortController();
fetch(url, { signal: controller.signal });
controller.abort();                                     // cancels the request

const sleep = ms => new Promise(r => setTimeout(r, ms));

async function retry(fn, tries = 3) {
  for (let i = 0; i < tries; i++) {
    try { return await fn(); }
    catch (e) { if (i === tries - 1) throw e; await sleep(2 ** i * 500); }
  }
}
Enter fullscreen mode Exit fullscreen mode

Async iteration

for await (const chunk of stream) { }                    // consume async iterables
const all = await Array.fromAsync(asyncGenerator());     // ES2026: collect an async iterable into an array
Enter fullscreen mode Exit fullscreen mode

fetch cheat

const res = await fetch('/api/items', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Pen' }),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
Enter fullscreen mode Exit fullscreen mode

16. Error handling

try {
  JSON.parse('{ bad json');
} catch (err) {
  console.error(err.name, err.message);   // SyntaxError ...
} finally {
  cleanup();                              // always runs
}
Enter fullscreen mode Exit fullscreen mode
Built-in error Typical cause
TypeError Wrong type, undefined.x, calling a non-function
ReferenceError Variable does not exist (or TDZ)
SyntaxError Bad syntax or bad JSON
RangeError Value out of range, infinite recursion
AggregateError Many errors at once (Promise.any)

Custom errors and cause

class ValidationError extends Error {
  constructor(message, field, options) {
    super(message, options);
    this.name = 'ValidationError';
    this.field = field;
  }
}

try {
  await save();
} catch (err) {
  throw new Error('Could not save profile', { cause: err });   // keeps the original error
}
Enter fullscreen mode Exit fullscreen mode
  • You can throw anything, but throw Error objects so you get a stack trace.
  • Error.isError(x) (ES2026) is a reliable check that works across realms (iframes), unlike instanceof.
  • try/catch catches sync errors and awaited rejections. It does not catch errors inside un-awaited promises or callbacks.
  • Handle global fallbacks: window.addEventListener('unhandledrejection', ...) in browsers, process.on('unhandledRejection', ...) in Node.

17. Iterators and generators

An iterable has a [Symbol.iterator]() method that returns an iterator (an object with next() returning { value, done }). for...of, spread and destructuring all use this.

function* range(start, end) {
  for (let i = start; i < end; i++) yield i;     // pauses here until next() is called
}

[...range(0, 3)];                                // [0, 1, 2]
Enter fullscreen mode Exit fullscreen mode

Generators are lazy: they compute values only when asked, so they can be infinite.

Iterator helpers (ES2025)

function* naturals() { let n = 0; while (true) yield n++; }

naturals()
  .filter(n => n % 2 === 0)
  .map(n => n * n)
  .take(5)
  .toArray();                  // [0, 4, 16, 36, 64]
Enter fullscreen mode Exit fullscreen mode

Helpers: map, filter, take, drop, flatMap, reduce, toArray, forEach, some, every, find. Use Iterator.from(iterable) for other iterables. Iterator.concat(a, b) (ES2026) chains iterators.


18. JSON, dates and Intl

JSON

JSON.stringify({ a: 1, b: [2, 3] }, null, 2);   // pretty print
JSON.parse('{"a":1}');                          // throws SyntaxError on bad input
JSON.parse(text, (key, value) => key === 'date' ? new Date(value) : value);   // reviver
Enter fullscreen mode Exit fullscreen mode

JSON.stringify surprises:

  • undefined, functions and symbols are dropped in objects (become null in arrays).
  • NaN and Infinity become null.
  • Date becomes an ISO string (via toJSON), and does not come back as a Date.
  • Circular references and BigInt throw.
  • Map and Set become {}.

Dates

const d = new Date();                       // now
new Date('2026-10-23');                     // date-only strings are parsed as UTC
new Date('2026-10-23T10:00');               // date-time without zone is parsed as LOCAL
new Date(2026, 9, 23);                      // month is 0-based: 9 means October
d.getTime();  Date.now();                   // ms since 1970 (Unix epoch)
d.toISOString();                            // '2026-10-23T...Z'
Enter fullscreen mode Exit fullscreen mode
  • Date is mutable, has weak time zone support, and a confusing API.
  • Temporal is the proposed modern replacement. Several blog posts list it under ES2026, but it is not in the ES2026 spec. Check MDN and caniuse for current engine support before using it.
  • For now: store UTC (toISOString()), format with Intl, or use a small library (date-fns, Day.js).

Intl (formatting without libraries)

new Intl.NumberFormat('en-IN', { style: 'currency', currency: 'INR' }).format(1234567.5);
// '₹12,34,567.50'

new Intl.DateTimeFormat('en-IN', { dateStyle: 'medium', timeStyle: 'short' }).format(new Date());

new Intl.RelativeTimeFormat('en', { numeric: 'auto' }).format(-1, 'day');   // 'yesterday'
new Intl.ListFormat('en').format(['A', 'B', 'C']);                          // 'A, B, and C'
Enter fullscreen mode Exit fullscreen mode

Also useful: structuredClone(), crypto.randomUUID(), URL and URLSearchParams:

const url = new URL('https://x.com/search?q=js');
url.searchParams.get('q');            // 'js'
url.searchParams.set('page', '2');
Enter fullscreen mode Exit fullscreen mode

19. Regular expressions

const re = /pattern/flags;
const re2 = new RegExp('pattern', 'g');
Enter fullscreen mode Exit fullscreen mode
Syntax Meaning
\d \w \s Digit, word char, whitespace (uppercase = opposite)
. Any char except newline (use s flag to include it)
^ $ Start, end
* + ? {2,4} 0+, 1+, 0 or 1, range (add ? to make it lazy)
[abc] [^abc] [a-z] Character classes
(x) (?:x) (?<name>x) Capture, non-capture, named capture
`x\ y`
(?=x) (?!x) Lookahead (positive, negative)
(?<=x) (?<!x) Lookbehind
Flag Meaning
g All matches
i Case-insensitive
m ^/$ match per line
s . matches newline
u / v Unicode mode (v adds set operations)
y Sticky
d Match indices
/\d+/.test('abc123');                                  // true
'a1b22'.match(/\d+/g);                                 // ['1', '22']
'2026-10-23'.match(/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/).groups.y;   // '2026'
[...'a1b22'.matchAll(/\d+/g)].map(m => m[0]);          // ['1', '22']
'a-b-c'.replaceAll('-', '+');                          // 'a+b+c'

const safe = new RegExp(RegExp.escape(userInput), 'i');   // ES2025: escape user text for a regex
Enter fullscreen mode Exit fullscreen mode

A regex with the g flag keeps lastIndex between .test() calls, which causes alternating true/false bugs. Do not reuse a global regex with .test().
Beware catastrophic backtracking (ReDoS) on user input with nested quantifiers like (a+)+$.


20. Browser essentials (DOM and Web APIs)

Select and change the DOM

const el = document.querySelector('.card');            // first match
const all = document.querySelectorAll('li');           // NodeList (use for...of)

el.textContent = 'Safe text';                          // use this for user data
el.innerHTML = '<b>HTML</b>';                          // XSS risk with untrusted input
el.classList.add('active');  el.classList.toggle('open');
el.dataset.id;                                         // reads data-id
el.setAttribute('aria-expanded', 'true');

const li = document.createElement('li');
li.textContent = 'New';
list.append(li);
li.remove();
Enter fullscreen mode Exit fullscreen mode

Events

button.addEventListener('click', e => {
  e.preventDefault();         // stop default behavior (link, form submit)
  e.stopPropagation();        // stop bubbling
}, { once: true });           // options: once, passive, capture, signal
Enter fullscreen mode Exit fullscreen mode

Phases: capture (top to target), target, bubble (target back up). Most events bubble.

Event delegation (one listener for many children, works for items added later):

list.addEventListener('click', e => {
  const item = e.target.closest('li[data-id]');
  if (!item || !list.contains(item)) return;
  console.log(item.dataset.id);
});
Enter fullscreen mode Exit fullscreen mode

Storage and other APIs

API Use Notes
localStorage Persistent key-value Strings only, sync, about 5 MB, never store secrets
sessionStorage Per-tab storage Cleared when the tab closes
Cookies Server-readable Use HttpOnly, Secure, SameSite for auth
IndexedDB Large structured data Async
fetch HTTP See section 15
IntersectionObserver Lazy loading, infinite scroll Better than scroll listeners
ResizeObserver, MutationObserver Watch size or DOM changes
requestAnimationFrame Smooth animation Runs before the next paint
AbortController Cancel fetch and listeners
Web Workers Heavy work off the main thread No DOM access
localStorage.setItem('user', JSON.stringify(user));
const saved = JSON.parse(localStorage.getItem('user') ?? 'null');
Enter fullscreen mode Exit fullscreen mode

21. Performance and memory

  • Do less work on the main thread. Long tasks block clicks and rendering. Move heavy work to Web Workers or break it up.
  • Debounce input handlers and throttle scroll/resize handlers (section 9).
  • Batch DOM writes, avoid reading layout (offsetHeight) between writes.
  • Lazy load with dynamic import() and IntersectionObserver.
  • Use Map/Set for lookups instead of arr.includes/arr.find inside loops (O(1) vs O(n)).
  • Do not optimize without measuring: DevTools Performance and Memory tabs.

Garbage collection and leaks

JavaScript frees memory when an object is unreachable. Leaks are things you accidentally keep reachable:

Leak Fix
Forgotten setInterval or listeners clearInterval, removeEventListener, AbortController signals
Detached DOM nodes still referenced Null out references
Accidental globals (x = 1 without declaration) Use const/let, strict mode
Closures holding huge data Keep only what you need
Unbounded caches Limit size, or use WeakMap

22. Security basics

  • XSS: never put untrusted text into innerHTML, outerHTML, document.write, or eval. Use textContent, or sanitize with DOMPurify. Add a Content Security Policy.
  • Avoid eval() and new Function() with any dynamic input.
  • Prototype pollution: merging untrusted JSON into objects with keys like __proto__ can modify Object.prototype. Validate keys, use Map, or Object.create(null).
  • Never trust the client. Validate on the server too. Never ship secrets or API keys in frontend code.
  • Tokens: prefer HttpOnly cookies over localStorage for session tokens.
  • Supply chain: commit your lockfile, run npm audit, review new dependencies, pin versions for critical packages.
  • ReDoS: be careful with complex regex on user input.

23. ES2015 to ES2026 at a glance

Edition Highlights
ES2015 let/const, arrow functions, classes, modules, template literals, destructuring, spread/rest, Promises, Map/Set, Symbol, generators, for...of
ES2016 **, Array.prototype.includes
ES2017 async/await, Object.values/entries, padStart/padEnd
ES2018 Object rest/spread, async iteration, Promise.finally, regex named groups, lookbehind, s flag
ES2019 flat/flatMap, Object.fromEntries, optional catch binding, trimStart/trimEnd
ES2020 ?., ??, BigInt, dynamic import(), Promise.allSettled, globalThis, matchAll
ES2021 replaceAll, Promise.any, ??= `\
ES2022 Top-level {% raw %}await, class fields and #private, static blocks, at(), Object.hasOwn, Error cause, regex d flag
ES2023 toSorted, toReversed, toSpliced, with, findLast, findLastIndex
ES2024 Object.groupBy, Map.groupBy, Promise.withResolvers, resizable ArrayBuffer, regex v flag, isWellFormed
ES2025 Iterator helpers, Set methods (union, etc.), Promise.try, RegExp.escape, JSON modules, regex modifiers, Float16Array
ES2026 Array.fromAsync, Error.isError, Iterator.concat, Math.sumPrecise, Uint8Array base64/hex methods, JSON.parse source text access, Map/WeakMap getOrInsert

Reality check on ES2026: this table follows the published ES2026 spec. Some articles list Temporal and explicit resource management (using) as ES2026, but they are not in that spec. Always check MDN compatibility tables or caniuse before shipping the newest features without a fallback.


Gotchas that bite everyone

  1. == coercion. Use ===.
  2. typeof null is 'object'. Check with === null.
  3. 0.1 + 0.2 !== 0.3. Compare with an epsilon or use integers (paise, cents).
  4. [10, 9, 1].sort() sorts as strings. Pass a comparator.
  5. var in loops with closures gives surprising output. Use let.
  6. Lost this when passing a method as a callback. Use arrow functions or bind.
  7. forEach with await does not wait. Use for...of or Promise.all.
  8. fetch does not reject on HTTP errors. Check res.ok.
  9. || vs ??. 0 || 5 is 5, 0 ?? 5 is 0.
  10. Shallow copies. Spread does not copy nested objects. Use structuredClone.
  11. const does not freeze. It only locks the binding.
  12. parseInt('08') style bugs. Always pass radix, or use Number().
  13. arr.map(parseInt) returns [1, NaN, NaN] (the index is passed as radix).
  14. new Date('2026-10-23') is UTC but new Date('2026-10-23T00:00') is local.
  15. Array holes. new Array(3) is empty, map skips holes. Use Array.from({ length: 3 }).
  16. Unhandled promise rejections crash Node and hide bugs. Always catch.
  17. Mutating while iterating. Do not splice inside forEach. Build a new array.
  18. Floating this in setTimeout(obj.method). Wrap in an arrow function.

Predict the Output

Try each one before reading the answer.

console.log([] == ![]);                    // true   ([] == false, '' == 0, 0 == 0)
console.log('5' + 3, '5' - 3);             // '53' 2
console.log([1, 2, 3] + [4]);              // '1,2,34'
console.log([10, 9, 1].sort());            // [1, 10, 9]
console.log(typeof null, typeof NaN);      // 'object' 'number'
console.log(0.1 + 0.2 === 0.3);            // false
console.log(['1', '2', '3'].map(parseInt)); // [1, NaN, NaN]
Enter fullscreen mode Exit fullscreen mode
for (var i = 0; i < 3; i++) setTimeout(() => console.log(i), 0);
// 3 3 3
Enter fullscreen mode Exit fullscreen mode
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');
// A D C B
Enter fullscreen mode Exit fullscreen mode
const user = { name: 'Asha', hi() { return this.name; } };
const f = user.hi;
f();   // this is lost: TypeError in strict mode (undefined.name), or globalThis.name in sloppy mode
Enter fullscreen mode Exit fullscreen mode
async function a() { console.log(1); await null; console.log(2); }
a(); console.log(3);
// 1 3 2 (code after await runs as a microtask)
Enter fullscreen mode Exit fullscreen mode

Interview Rapid Fire

Question Short answer
What is JavaScript? A single-threaded, dynamically typed, multi-paradigm language with first-class functions, run by engines like V8.
var vs let vs const? var is function-scoped and hoisted as undefined. let and const are block-scoped with a TDZ. const cannot be reassigned.
What is hoisting? Declarations are registered before code runs. Functions fully, var as undefined, let/const stay in the TDZ.
== vs ===? == coerces types, === does not. Prefer ===.
What are primitives? string, number, bigint, boolean, undefined, null, symbol. Immutable, copied by value.
What is a closure? A function plus the variables from where it was created. Gives private state.
What is this? Set by how a function is called: new, call/apply/bind, method call, default. Arrows use lexical this.
Arrow vs regular function? Arrows have no own this, arguments, or new. Use them for callbacks, not for object methods.
call vs apply vs bind? call and apply invoke now (args listed vs array). bind returns a new function.
What is the prototype chain? Objects inherit through a linked chain of prototypes until null.
What is the event loop? Runs sync code, then all microtasks, then one macrotask, repeat. Makes async work on a single thread.
Microtask vs macrotask? Microtasks: Promise callbacks, queueMicrotask. Macrotasks: timers, events, I/O. Microtasks run first.
What is a Promise? An object for a future value with states pending, fulfilled, rejected.
Promise.all vs allSettled vs race vs any? All fulfill or fail fast. All settle. First to settle. First to fulfill.
What does async/await do? Syntax over Promises. async returns a Promise, await pauses that function until it settles.
How do you run async tasks in parallel? Start them together, then await Promise.all([...]).
Shallow vs deep copy? Shallow copies one level (spread). Deep copies everything (structuredClone).
null vs undefined? undefined means not assigned. null means intentionally empty.
What is event delegation? One listener on a parent that handles child events using e.target.
Event bubbling vs capturing? Bubbling goes target to root (default). Capturing goes root to target.
map vs forEach? map returns a new array. forEach returns nothing, use it for side effects.
slice vs splice? slice copies a portion. splice mutates the array.
What is currying? Turning f(a, b) into f(a)(b).
What is debouncing? Delay the call until the user stops triggering it.
for...in vs for...of? in loops keys (including inherited). of loops values of iterables.
What are generators? Functions that can pause with yield and resume. Lazy sequences.
Map vs object? Map allows any key type, keeps order, has size, and performs better for frequent changes.
WeakMap use case? Attach data to objects without preventing garbage collection.
ESM vs CommonJS? ESM uses import/export, is static and async-capable. CJS uses require, is sync and dynamic.
What is a pure function? Same input gives same output, with no side effects.
How do you prevent memory leaks? Remove listeners and timers, avoid accidental globals, limit caches, use WeakMap.
What is strict mode? Opt-in stricter parsing and error behavior. Default in modules and classes.
What is Symbol? A unique, immutable primitive, used for hidden keys and protocols like Symbol.iterator.
Object.freeze vs const? const locks the binding. freeze blocks changes to the object's own properties (shallowly).

27. Official resources


Final tip

Do not try to memorize this in one go. Build small things (a todo app, a weather widget, a CLI script), return here when something breaks, and the patterns will stick. Master the core (scope, closures, this, the event loop, promises) and everything else gets easier.

If this helped, save it for revision or interview prep. Next up in the series: Next.js.

Found something outdated or wrong? Drop a comment and I will fix it.

Top comments (0)