Dev.to WebDev 🛠 Dev 👁 0 📖 25 min read

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:

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

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

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 = () => {};

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 ==)

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

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

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)

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)

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

6. Strings, numbers and Math

Strings (immutable)

const name = 'World';
`Hello, ${name}! ${2 + 3}`;     // template literal, multi-line allowed
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]

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');
}
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; }
}

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 ()

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

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'
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

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

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

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)

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); }
  };
}

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)

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

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] }

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

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

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

Real-world pipeline

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

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);

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;

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);

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

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

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)

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)
  • 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

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

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());
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

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();
  }
}
  • 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)

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

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); }
  }
}

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

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();

16. Error handling

try {
  JSON.parse('{ bad json');
} catch (err) {
  console.error(err.name, err.message);   // SyntaxError ...
} finally {
  cleanup();                              // always runs
}
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
}
  • 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]

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]

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

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'
  • 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'

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');

19. Regular expressions

const re = /pattern/flags;
const re2 = new RegExp('pattern', 'g');
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

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();

Events

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

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);
});

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');

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]
for (var i = 0; i < 3; i++) setTimeout(() => console.log(i), 0);
// 3 3 3
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');
// A D C B
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
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)

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.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.