technology · javascript

The JavaScript Cheatsheet Collection

KDP Book Manifest & Metadata
Click to Expand & CopyManifest

Use the copy buttons below to copy metadata verbatim into the Amazon KDP Publishing forms.

Book Title
Subtitle
Target Audience
BISAC Subject Code
Keywords (Comma Separated)
Book Description (HTML)
KDP Categories
  • Books > Computers & Technology > Programming > Languages > JavaScript
  • Books > Computers & Technology > Web Development > Web Programming
  • Books > Computers & Technology > Software Development & Engineering > Tools

The JavaScript Cheatsheet Collection

A Simple, Scannable Quick Reference Guide for Modern Web Developers

usefulcheatsheets.com

The JavaScript Cheatsheet Collection

First Edition: 2026

Copyright © 2026 by usefulcheatsheets.com. All rights reserved.

No part of this book may be reproduced in any form or by any electronic or mechanical means, including information storage and retrieval systems, without written permission from the publisher, except for the use of brief quotations in a book review.

Publisher: usefulcheatsheets.comISBN: Not ApplicableBISAC Subject Code: COM051260

Welcome to the JavaScript Masterclass

JavaScript is a key topic in Technology development.

This reference book compiles comprehensive cheatsheets covering everything from fundamentals to advanced patterns.

Use this book as a daily reference or read it linearly to build your knowledge.

How to Use This Book

Each page is a visual cheatsheet with core concepts, practical steps, code snippets, and warnings.

usefulcheatsheets.com | Introduction
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Array Methods
Chapter 01 · Page 8
Beginner

JavaScript Array Methods

A quick reference for adding, transforming, searching, and ordering items in JavaScript arrays.

TL;DR

  1. 01Use push(), pop(), shift(), and unshift() to add or remove items.
  2. 02Use map(), filter(), and reduce() to transform array data.
  3. 03Use find(), some(), and includes() to search arrays.

Tips

  1. 01Prefer non-mutating methods like map, filter, and slice when you want to keep your original array unchanged.
  2. 02Chain map, filter, and reduce together to transform data in one readable pipeline instead of writing several separate loops.

Warnings

  1. 01Sort and reverse change the original array in place, so copy first if you need to keep the source order.
  2. 02splice() also mutates the original array, and the wrong delete count can silently remove items you meant to keep.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Array Methods
Chapter 01 · Page 9
Beginner

JavaScript Array Methods

(continued)

Add and Remove

  • push()

    Adds one or more items to the end, returns the new length.

    const cart = ['apple'];
    cart.push('banana'); // 2
  • pop()

    Removes and returns the last item.

    const stack = ['init', 'save', 'close'];
    stack.pop(); // 'close'
  • shift()

    Removes and returns the first item.

    const queue = ['first', 'second', 'third'];
    queue.shift(); // 'first'
  • unshift()

    Adds one or more items to the front, returns the new length.

    const updates = ['old'];
    updates.unshift('new'); // 2
  • splice()

    Inserts, removes, or replaces items at any index. Mutates in place.

    const list = ['a', 'b', 'c'];
    list.splice(1, 1, 'x'); // returns ['b']
    // list is now ['a', 'x', 'c']
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Array Methods
Chapter 01 · Page 10
Beginner

JavaScript Array Methods

(continued)

Copy and Combine

  • concat()

    Merges two or more arrays into a new array without mutation.

    const arr1 = [1, 2];
    arr1.concat([3, 4]); // [1, 2, 3, 4]
  • spread operator

    Copies or combines arrays cleanly without mutation.

    const a = [1, 2];
    const b = [...a, 3];               // [1, 2, 3]
    const merged = [...a, ...b, ...c]; // all combined
  • slice()

    Copies a whole array or a portion without mutating the source.

    const arr = [1, 2, 3, 4];
    arr.slice(1, 3); // [2, 3]
  • Array.of()

    Builds a new array from arguments, even a single number.

    Array.of(7); // [7]
    Array(7);    // empty array with length 7
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Array Methods
Chapter 01 · Page 11
Beginner

JavaScript Array Methods

(continued)

Transform Data

  • map()

    Creates a new array by transforming every element with a function.

    const prices = [10, 20, 30];
    prices.map(p => p * 1.1); // [11, 22, 33]
  • filter()

    Returns a new array keeping only items that pass the test.

    const users = [{active: true}, {active: false}];
    users.filter(u => u.active); // [{active: true}]
  • reduce()

    Combines all items into a single value; always pass an initial value.

    const nums = [1, 2, 3];
    nums.reduce((acc, n) => acc + n, 0); // 6
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Array Methods
Chapter 01 · Page 12
Beginner

JavaScript Array Methods

(continued)

Search and Test

  • find()

    Returns the first element matching a condition, or undefined.

    users.find(u => u.id === 1); // {id: 1, ...}
  • findIndex()

    Returns the index of the first match, or -1 if not found.

    users.findIndex(u => u.id === 1); // 0
  • includes()

    Returns true if the exact value exists in the array.

    ['read', 'write'].includes('write'); // true
  • some()

    Returns true if at least one element passes the test.

    users.some(u => u.isAdmin); // true or false
  • every()

    Returns true only if all elements pass the test.

    tasks.every(t => t.done); // true or false
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Array Methods
Chapter 01 · Page 13
Beginner

JavaScript Array Methods

(continued)

Order and Display

  • sort()

    Sorts the array in place; always pass a comparator for reliable results.

    names.sort((a, b) => a.localeCompare(b));
  • reverse()

    Flips the order of items in place.

    [1, 2, 3].reverse(); // [3, 2, 1]
  • join()

    Combines all elements into a string with a separator.

    ['a', 'b', 'c'].join(','); // "a,b,c"
  • forEach()

    Runs a function on each item for side effects; returns undefined.

    items.forEach(item => console.log(item));
  • Array.from()

    Converts any iterable — string, Set, NodeList — into a real array.

    Array.from('hi');             // ['h', 'i']
    Array.from(new Set([1,1,2])); // [1, 2]
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Array Methods
Chapter 01 · Page 14
Beginner

JavaScript Array Methods

(continued)

Flatten and Access

  • flat()

    Collapses nested arrays one level deep; pass a depth to go deeper.

    const nested = [1, [2, [3]]];
    nested.flat();   // [1, 2, [3]]
    nested.flat(2);  // [1, 2, 3]
  • flatMap()

    Maps over items and flattens the result one level in a single pass.

    const words = ['hi there', 'foo bar'];
    words.flatMap(s => s.split(' '));
    // ['hi', 'there', 'foo', 'bar']
  • at()

    Accesses an element by index; negative values count from the end.

    const arr = [10, 20, 30, 40];
    arr.at(0);  // 10
    arr.at(-1); // 40
  • fill()

    Overwrites a range of elements with a static value in place.

    const arr = [1, 2, 3, 4, 5];
    arr.fill(0, 1, 3); // [1, 0, 0, 4, 5]
  • Array.isArray()

    Safely checks whether a value is an array at runtime.

    Array.isArray([1, 2]); // true
    Array.isArray('abc'); // false
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Array Methods
Chapter 01 · Page 15
Beginner

JavaScript Array Methods

(FAQ)

FAQ

Use [...new Set(array)] to deduplicate primitives in one line. For objects, filter by a unique key instead: array.filter((item, i, arr) => arr.findIndex(x => x.id === item.id) === i).

map() returns a new array of transformed values and is chainable. forEach() always returns undefined and exists purely for side effects. If you need the result, use map().

Use findIndex() with a callback — it returns the index of the first match or -1 if none found. Use indexOf() only when searching for an exact primitive value, since it can't accept a predicate.

Use the spread operator: const merged = [...arr1, ...arr2], or arr1.concat(arr2). Both return a new array and leave the originals unchanged.

Without an initial value, reduce() uses the first element as the accumulator and starts iterating at index 1. This silently breaks with empty arrays, which throw, or when the first element is the wrong type. Always pass an explicit initial value as the second argument.

[1, 2, 3].reduce((sum, n) => sum + n, 0); // 6
[].reduce((sum, n) => sum + n, 0);        // 0
[].reduce((sum, n) => sum + n);           // TypeError
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Array Methods
Chapter 01 · Page 16
Beginner

JavaScript Array Methods

(In Practice)
In Practice

Filter, Map, Sort, Then Reduce

Chains filter, map, sort, and reduce on an order list to compute tax-adjusted revenue in one readable pipeline.

  1. 01filter() removes pending and cancelled orders before they reach the revenue calculation.
  2. 02map() adds a tax-adjusted total field to each order without mutating the originals.
  3. 03sort() reorders results from highest to lowest total.
  4. 04reduce() sums every total into a single revenue figure, starting from zero.
  5. 05at(0) retrieves the top order; negative indexes like at(-1) work too.
const orders = [
  { name: 'Keyboard', price: 89.99,  status: 'completed' },
  { name: 'Monitor',  price: 349.99, status: 'pending' },
  { name: 'Mouse',    price: 49.99,  status: 'completed' },
  { name: 'Webcam',   price: 79.99,  status: 'completed' },
  { name: 'Headset',  price: 129.99, status: 'cancelled' },
];

const summary = orders
  .filter(o => o.status === 'completed')
  .map(o => ({ ...o, total: +(o.price * 1.08).toFixed(2) }))
  .sort((a, b) => b.total - a.total);

const revenue = summary.reduce((acc, o) => acc + o.total, 0);

console.log('Top order:', summary.at(0).name); // 'Keyboard'
console.log(`Revenue (after tax): $${revenue.toFixed(2)}`); // $237.57
Takeaway

Chain filtermapsortreduce to build a full data pipeline — one concern per step.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Arrow Functions
Chapter 02 · Page 17
Beginner

JavaScript Arrow Functions

Learn arrow function syntax, implicit returns, and lexical this with clear practical examples.

TL;DR

  1. 01Write concise callbacks using => instead of the function keyword.
  2. 02Skip return and braces for one-line expressions with implicit returns.
  3. 03Inherit this from the enclosing scope instead of redefining it.

Tips

  1. 01Use arrow functions for short callbacks inside map() and filter(), since they keep the code easy to scan.
  2. 02Name longer arrow functions by assigning them to a const, since stack traces then show the variable name.

Warnings

  1. 01Do not use arrow functions as methods on objects when those methods need access to the object through this.
  2. 02Arrow functions cannot be used as constructors, so calling one with new throws a TypeError instead of creating an instance.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Arrow Functions
Chapter 02 · Page 18
Beginner

JavaScript Arrow Functions

(continued)

Basic Syntax

  • One parameter

    Drop the parentheses when the function takes exactly one parameter.

    const double = n => n * 2;
    double(4); // 8
  • Multiple parameters

    Wrap parameters in parentheses when the function takes two or more.

    const multiply = (a, b) => a * b;
    multiply(2, 5); // 10
  • No parameters

    Use empty parentheses when the function takes no parameters at all.

    const greet = () => 'Hello!';
    greet(); // "Hello!"
  • Anonymous by default

    Arrow functions are anonymous and are usually assigned to a variable.

    const handlers = [];
    handlers.push(() => console.log('clicked'));
  • Use const

    Assign arrow functions with `const` to prevent accidental, silent reassignment.

    const sayHi = () => 'Hi';
    sayHi = () => 'Yo'; // throws TypeError
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Arrow Functions
Chapter 02 · Page 19
Beginner

JavaScript Arrow Functions

(continued)

Returning Values

  • Implicit return

    Drop the braces and the return keyword to return a single expression.

    const sum = (a, b) => a + b;
  • Block body

    Use curly braces with return for multi-line function bodies and logic.

    const check = num => {
      if (num > 10) return 'big';
      return 'small';
    };
  • Object literal

    Wrap returned object literals in parentheses to avoid a syntax error.

    const make = id => ({ id, active: true });
  • Array methods

    Implicit returns work well inside array methods like `filter()` and `map()`.

    const evens = [1, 2, 3, 4]
      .filter(n => n % 2 === 0)
      .map(n => n * 10); // [20, 40]
  • Pick a style

    Match the return style to the code's complexity and readability needs.

    const isEven = n => n % 2 === 0;  // implicit
    const classify = n => {           // block
      if (n < 0) return 'negative';
      return n % 2 === 0 ? 'even' : 'odd';
    };
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Arrow Functions
Chapter 02 · Page 20
Beginner

JavaScript Arrow Functions

(continued)

Promise and Async Patterns

  • Promise chains

    Most real-world arrow functions live inside `.then()`, `.catch()`, or async wrappers.

    fetch('/api/user')
      .then(res => res.json())
      .then(data => console.log(data))
      .catch(err => console.error(err));
  • Promise.all()

    Run independent async calls together and destructure results once every promise resolves.

    const loadDashboard = async () => {
      const [users, posts] = await Promise.all([
        fetch('/api/users').then(r => r.json()),
        fetch('/api/posts').then(r => r.json()),
      ]);
    };
  • Async arrow

    Use an arrow function as the body of an async function for compact definitions.

    const getUser = async (id) => {
      const res = await fetch(`/users/${id}`);
      return res.json();
    };
  • Async IIFE

    Run an async arrow immediately when you need `await` outside any named function.

    (async () => {
      const data = await fetchDashboardStats();
      console.log(data);
    })();
  • try/catch

    Wrap `await` calls in `try/catch` to handle rejected promises inside async arrows.

    const loadUser = async (id) => {
      try {
        const res = await fetch(`/users/${id}`);
        return await res.json();
      } catch (err) {
        console.error('Failed to load user', err);
      }
    };
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Arrow Functions
Chapter 02 · Page 21
Beginner

JavaScript Arrow Functions

(continued)

Lexical This

  • Arrow inherits this

    An arrow function inherits `this` from its surrounding scope, so it stays bound.

    function Timer() {
      this.count = 0;
      setInterval(() => this.count++, 1000);
    }
  • Regular function this

    A regular function creates its own `this`, which can cause unexpected values.

    function Timer() {
      this.count = 0;
      setInterval(function () {
        this.count++; // this is wrong here
      }, 1000);
    }
  • Class methods

    This behavior makes callbacks inside class methods work without manual binding.

    class Counter {
      count = 0;
      increment = () => { this.count++; };
    }
  • Method callbacks

    Arrow callbacks inside a method inherit `this` from that method, not the caller.

    const cart = {
      items: [{ price: 10 }, { price: 25 }],
      total() {
        return this.items.reduce(
          (sum, i) => sum + i.price, 0
        );
      },
    };
    cart.total(); // 35
  • Event listeners

    Bind event handlers with arrow functions so `this` still points at the class instance.

    class Button {
      clicks = 0;
      constructor(el) {
        el.addEventListener('click', () => {
          this.clicks++;
        });
      }
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Arrow Functions
Chapter 02 · Page 22
Beginner

JavaScript Arrow Functions

(continued)

Limitations

  • No arguments object

    Arrow functions have no `arguments` object; use rest parameters to collect arguments instead.

    function legacyLogger() {
      return arguments.length;
    }
    const modernLogger = (...args) => args.length;
  • No constructors

    Arrow functions cannot be used as constructors with the `new` keyword.

    const Person = (name) => { this.name = name; };
    new Person('Alex'); // throws: not a constructor
  • No generators

    Arrow functions cannot be used as generator functions with `yield`.

    function* range(n) {
      for (let i = 0; i < n; i++) yield i;
    }
    [...range(3)]; // [0, 1, 2]
  • No prototype

    Arrow functions have no `prototype` property, since they can never act as constructors.

    const Greeter = () => {};
    Greeter.prototype; // undefined
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Arrow Functions
Chapter 02 · Page 23
Beginner

JavaScript Arrow Functions

(FAQ)

FAQ

Use arrow functions for short, inline callbacks like those passed to map(), filter(), or setTimeout(). Stick with regular functions when you need your own this binding, the arguments object, or when defining object methods.

Wrap the object literal in parentheses: const getUser = () => ({ name: 'Alice', age: 30 }). Without the parentheses, the curly braces are parsed as a function body instead of an object.

Arrow functions capture this from the enclosing lexical scope at definition time, not the call site. If you need this to refer to a specific object at runtime, use a regular function instead.

No, arrow functions cannot act as constructors and throw a TypeError when called with new. They also lack a prototype property, so use a regular function or a class to instantiate objects.

The concise body form () => value implicitly returns the expression with no braces or return keyword. The block body form () => { return value; } uses an explicit return. Use the block form for multiple statements.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Arrow Functions
Chapter 02 · Page 24
Beginner

JavaScript Arrow Functions

(In Practice)
In Practice

Formatting a Product List with Arrow Functions

Chain arrow functions through filter and map to build a display-ready list of in-stock products with formatted prices.

  1. 01filter() keeps only products where inStock is true, using a one-line arrow function with an implicit return.
  2. 02map() returns a new object literal for each product, so the object needs to be wrapped in parentheses.
  3. 03A template literal inside the arrow function formats each price to two decimal places.
  4. 04The result is a fresh array — the original products array is never mutated.
const products = [
  { name: 'Desk Lamp', price: 24.5, inStock: true },
  { name: 'Notebook', price: 4.99, inStock: true },
  { name: 'Stapler', price: 12, inStock: false },
];

const display = products
  .filter(p => p.inStock)
  .map(p => ({ label: `${p.name} — $${p.price.toFixed(2)}` }));

console.log(display);
// [{ label: 'Desk Lamp — $24.50' }, { label: 'Notebook — $4.99' }]
Takeaway

Implicit-return arrow functions keep filter/map chains compact — just remember to wrap returned objects in parentheses.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Date and Time
Chapter 03 · Page 25
Beginner

JavaScript Date and Time

Create, format, and modify dates in JavaScript with timestamps, UTC, and common calculations.

TL;DR

  1. 01Create dates using new Date with several input options.
  2. 02Read date parts with getFullYear(), change them with setFullYear().
  3. 03Format dates with toISOString() for machines and toLocaleDateString() for humans.

Tips

  1. 01For complex date math like time zones, recurring events, or relative time, use a library like date-fns or Luxon.
  2. 02Store dates as ISO strings or timestamps in APIs and databases, converting to a Date object only for display.

Warnings

  1. 01JavaScript months are zero-indexed, so passing 0 means January and passing 11 means December, not month 12.
  2. 02Date string parsing varies by browser for non-ISO formats, so prefer ISO 8601 or new Date(year, month, day) instead.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Date and Time
Chapter 03 · Page 26
Beginner

JavaScript Date and Time

(continued)

Creating Dates

  • new Date()

    The Date constructor accepts four different argument shapes for creating dates.

    const now = new Date();
  • From milliseconds

    Pass a timestamp in milliseconds to create a date from a number.

    const fromMs = new Date(1697040000000);
  • From a string

    Pass a date string to parse a specific date in standard format.

    const d = new Date("2025-10-11");
  • From parts

    Pass year, month (zero-indexed), day, and time parts to build a custom date.

    const custom = new Date(2025, 9, 11, 15, 30);
  • Checking validity

    Detects an invalid date by testing whether getTime() returns NaN.

    Number.isNaN(d.getTime()); // true if invalid
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Date and Time
Chapter 03 · Page 27
Beginner

JavaScript Date and Time

(continued)

Reading Parts

  • getFullYear()

    Reads the four-digit year directly from a Date object instance.

    now.getFullYear(); // 2025
  • getMonth()

    Reads the month as a zero-indexed number, where zero means January.

    now.getMonth(); // 9 means October
  • getDate() and getDay()

    getDate() returns the day of the month; getDay() returns the weekday.

    now.getDate();
    now.getDay(); // 0 = Sunday
  • Time components

    Use getHours(), getMinutes(), and getSeconds() to read the time components.

    now.getHours();
    now.getMinutes();
    now.getSeconds();
  • getTime()

    Reads the date as a millisecond timestamp since the Unix epoch.

    now.getTime(); // ms since epoch
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Date and Time
Chapter 03 · Page 28
Beginner

JavaScript Date and Time

(continued)

Changing Parts

  • setFullYear()

    Every setter mutates the original Date object in place — there's no immutable version.

    const date = new Date();
    date.setFullYear(2026);
  • setMonth()

    Changes the month in place, again starting counting from zero.

    date.setMonth(0); // January
  • setDate()

    Changes the day of the month, rolling over into next month.

    date.setDate(1);
  • setHours()

    Use extra arguments to set minutes and seconds at the same time.

    date.setHours(12, 0, 0);
  • setTime()

    Sets the entire date at once from a millisecond timestamp value.

    date.setTime(0); // Jan 1, 1970 UTC
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Date and Time
Chapter 03 · Page 29
Beginner

JavaScript Date and Time

(continued)

Timestamps and UTC

  • Date.now()

    Returns the current timestamp in milliseconds since the Unix epoch.

    const ts = Date.now();
  • getUTC methods

    Reads times in universal coordinated time instead of the local timezone.

    now.getUTCFullYear();
    now.getUTCHours();
  • Easy comparisons

    Timestamps make it easy to compare or subtract two dates directly.

    date1.getTime() < date2.getTime();
  • toJSON()

    Runs automatically inside JSON.stringify(), which produces an ISO date string.

    JSON.stringify({ d: now }); // ISO string
  • new Date(ts)

    Convert any millisecond timestamp back into a usable Date object.

    const d = new Date(1700000000000);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Date and Time
Chapter 03 · Page 30
Beginner

JavaScript Date and Time

(continued)

Formatting and Math

  • toISOString()

    Formats a date for machines, always returning UTC in a sortable format.

    now.toISOString();
    // "2025-10-11T00:00:00.000Z"
  • toLocaleDateString()

    Formats the date for the user's region for a human-readable display.

    now.toLocaleDateString();
  • Adding days

    Read the current date and add to it to shift by any number of days.

    const today = new Date();
    today.setDate(today.getDate() + 5);
  • Subtracting dates

    Subtract two dates to get the difference in milliseconds between them.

    const diffMs = date1 - date2; // milliseconds
  • Converting units

    Convert milliseconds into days or hours using simple division for clarity.

    const hrs = ms / (1000 * 60 * 60);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Date and Time
Chapter 03 · Page 31
Beginner

JavaScript Date and Time

(FAQ)

FAQ

JavaScript's Date constructor takes months as zero-indexed values, so January is 0 and December is 11. Always subtract 1 when passing a human-readable month number, e.g. new Date(2024, 0, 15) for January 15th.

Use Date.now() to get milliseconds since the Unix epoch. Divide by 1000 and floor the result to get seconds: Math.floor(Date.now() / 1000). You can also call new Date().getTime() for the same millisecond result.

getMonth() returns the month in local time, based on the user's system timezone. getUTCMonth() always returns the month in UTC instead. Use UTC methods when working with server timestamps or storing dates that must be timezone-independent.

Read the current day with getDate(), add your offset, then set it back with setDate(), e.g. date.setDate(date.getDate() + 7). JavaScript automatically rolls over the month and year if the value exceeds the month's length. For anything more complex, like adding months or handling DST, use date-fns or Luxon.

Use toLocaleDateString() with a locale and options object: new Date().toLocaleDateString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit' }). For a sortable ISO format use toISOString(), which always returns UTC in the format YYYY-MM-DDTHH:mm:ss.sssZ.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Date and Time
Chapter 03 · Page 32
Beginner

JavaScript Date and Time

(In Practice)
In Practice

Calculating Days Until a Deadline

Creates a target date, computes the whole-day difference from today, and formats both dates for display.

  1. 01new Date(year, month, day) builds the deadline — remember month is zero-indexed, so October is 9.
  2. 02Subtracting two Date objects returns the difference in milliseconds, not days.
  3. 03Dividing by the number of milliseconds in a day and rounding up gives a whole day count.
  4. 04toLocaleDateString() formats each date for display while the raw Date objects handle the math.
const today = new Date();
const deadline = new Date(2026, 9, 31); // October 31, 2026 (month is zero-indexed)

const msPerDay = 1000 * 60 * 60 * 24;
const daysLeft = Math.ceil((deadline - today) / msPerDay);

console.log(`Today: ${today.toLocaleDateString()}`);
console.log(`Deadline: ${deadline.toLocaleDateString()}`);
console.log(`${daysLeft} day(s) remaining`);
Takeaway

Date subtraction gives milliseconds — always divide by the right unit before displaying a day count.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Debugging Tools
Chapter 04 · Page 33
Beginner

JavaScript Debugging Tools

Quick debugging one-liners for logging, tracing, timing, and inspecting JavaScript values in any project.

TL;DR

  1. 01Log values with console.log() and inspect with console.dir().
  2. 02Pause execution with the debugger statement in DevTools.
  3. 03Measure performance with console.time() and console.timeEnd() using matching labels.

Tips

  1. 01Use console.table() for arrays of objects, since it shows each property as a column for fast visual scanning.
  2. 02Use the %c format specifier in console.log() to add custom CSS styling to messages, making important output easier to spot.

Warnings

  1. 01Remove debugger statements and console logs before shipping production code, since they slow down your app and expose data.
  2. 02console.log() shows a live reference to objects, so an expanded log can differ from the object's state at log time.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Debugging Tools
Chapter 04 · Page 34
Beginner

JavaScript Debugging Tools

(continued)

Logging Basics

  • console.log()

    The obvious choice, but several other console methods solve specific logging problems faster.

    console.log('user:', user);
  • Labeled logs

    Label your logs by passing a string prefix as the first argument.

    console.log('typeof myVar:', typeof myVar);
  • console.table()

    Displays an array of objects as a clean, scannable table instead of logs.

    console.table(users);
  • Combined values

    Combine multiple values in one log call to compare them side by side.

    console.log('before:', before, 'after:', after);
  • %o Specifier

    Embeds an inspectable object directly inside a formatted log string.

    console.log('user: %o', user);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Debugging Tools
Chapter 04 · Page 35
Beginner

JavaScript Debugging Tools

(continued)

Pausing and Tracing

  • debugger;

    A single statement pauses your entire script wherever DevTools is open.

    debugger;
  • console.trace()

    Prints the full call stack leading up to the current line of code.

    console.trace();
  • Conditional debugger

    Pauses only when a condition is true, instead of every single time.

    if (i === 5) debugger; // pause once
  • console.assert()

    Logs a message only when the given condition turns out false.

    console.assert(user.id, 'Missing user id');
  • console.count()

    Counts and logs how many times a labeled line has run.

    console.count('render'); // render: 1
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Debugging Tools
Chapter 04 · Page 36
Beginner

JavaScript Debugging Tools

(continued)

Checking Values

  • Strict equality

    Most "why is this undefined" bugs resolve faster with a strict equality check.

    console.log(myVar === undefined);
  • Nullish coalescing

    Log a fallback when values are missing using the ?? operator.

    console.log(myVar ?? 'fallback');
  • Falsy check

    Detect any falsy value with a simple negation check inside an if.

    if (!myVar) console.log('Falsy!');
  • typeof

    Use typeof when results seem off, to confirm the value's data type.

    typeof 'hi' === 'string'; // true
  • Number.isNaN()

    Checks for NaN without the risky type coercion of the global isNaN().

    Number.isNaN(NaN);  // true
    Number.isNaN('x');  // false
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Debugging Tools
Chapter 04 · Page 37
Beginner

JavaScript Debugging Tools

(continued)

Snapshotting Live Objects

  • JSON.stringify snapshot

    console.log(obj) shows the object's state when expanded, not when logged — this fixes that.

    console.log(JSON.stringify(obj, null, 2));
  • structuredClone()

    Takes a frozen deep copy for logging without mutating the live original.

    console.log(structuredClone(state));
  • console.dir()

    Renders a DOM node as an interactive property tree instead of HTML.

    console.dir(document.querySelector('button'));
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Debugging Tools
Chapter 04 · Page 38
Beginner

JavaScript Debugging Tools

(continued)

Timing and Errors

  • console.time/timeEnd

    A matching label is the only thing connecting console.time() to its console.timeEnd().

    console.time('label');
    // code here
    console.timeEnd('label');
  • console.group()

    Nests related log messages in a collapsible group for easier scanning.

    console.group('info');
    // related logs...
    console.groupEnd();
  • try...catch

    Wrap risky code in a try...catch block to handle errors safely.

    try {
      riskyFunction();
    } catch (e) {
      console.error('Error:', e.message);
    }
  • console.error()

    Prints errors in red with a full, clickable stack trace attached.

    console.error('Failed to save:', err);
  • console.warn()

    Flags non-fatal issues in yellow so they still catch your eye.

    console.warn('Approaching API rate limit');
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Debugging Tools
Chapter 04 · Page 39
Beginner

JavaScript Debugging Tools

(FAQ)

FAQ

console.log() prints a string representation of a value and is best for primitives and quick output. console.dir() renders an interactive property tree instead, which is far more useful for inspecting DOM nodes or complex objects. Use console.dir() when you need to drill into nested properties.

Add the debugger statement directly in your code. When DevTools is open and execution reaches that line, it pauses automatically. From there you can step through the call stack, inspect variables, and evaluate expressions in the console.

Wrap the code with console.time('label') before it runs and console.timeEnd('label') after. The browser logs the elapsed milliseconds to the console using the matching label. This identifies which measurement the output belongs to.

console.log() captures a live reference to objects, so expanding the output later shows the current state, not the logged state. Use console.log(JSON.stringify(obj)) or console.dir() to snapshot the value at the moment of logging.

In DevTools, open the Sources panel and enable 'Pause on exceptions' (the stop-sign icon). The debugger automatically breaks at the exact line that throws. This lets you inspect the local scope and call stack without manually adding breakpoints.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Debugging Tools
Chapter 04 · Page 40
Beginner

JavaScript Debugging Tools

(In Practice)
In Practice

Debugging a Slow Data Fetch

Combines console.time, console.table, and try/catch to time a fetch call, inspect its output, and catch failures.

  1. 01console.time('loadUsers') starts a labeled timer right before the fetch begins.
  2. 02console.table(users) renders the array of user objects as a scannable table instead of a nested log.
  3. 03The try/catch block logs a clear error message if the fetch or parsing fails.
  4. 04finally guarantees console.timeEnd('loadUsers') runs and reports the elapsed time either way.
async function loadUsers() {
  console.time('loadUsers');
  try {
    const res = await fetch('/api/users');
    const users = await res.json();
    console.table(users);
    return users;
  } catch (error) {
    console.error('Failed to load users:', error.message);
    return [];
  } finally {
    console.timeEnd('loadUsers');
  }
}

loadUsers();
// logs a table of users, then "loadUsers: 42.3ms"
Takeaway

Pair console.time/timeEnd with try/catch so you always see how long code took, even when it fails.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Destructuring
Chapter 05 · Page 41
Beginner

JavaScript Destructuring

Master object and array destructuring for cleaner variable assignment and function parameters.

TL;DR

  1. 01Extract object properties into variables with curly brace syntax.
  2. 02Extract array elements into variables with square bracket syntax.
  3. 03Use default values when properties or elements are missing.

Tips

  1. 01Use destructuring in function parameters to document what properties a function expects, making code more readable and self-documenting.
  2. 02Combine destructuring with rest syntax to pull out a few named values while collecting the remaining properties into one object.
  3. 03Rename destructured variables to avoid naming collisions when two objects in the same scope share a property name.

Warnings

  1. 01Destructuring doesn't create new properties on objects — it just assigns values to variables in the local scope.
  2. 02Destructuring a null or undefined value throws a TypeError immediately, so guard against missing data before destructuring it.
  3. 03Default values only apply when a property is undefined, so a falsy value like false or 0 still wins.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Destructuring
Chapter 05 · Page 42
Beginner

JavaScript Destructuring

(continued)

Object Destructuring

  • Basic extraction

    Extract properties from an object into separate variables.

    const user = { name: "Alice", age: 30 };
    const { name, age } = user;
    console.log(name); // "Alice"
  • Exact key match

    Property names must match the object keys exactly.

    const { name, email } = user;
    // name is available, but email is undefined
  • Extract only what you need

    Destructure only the properties you need from an object.

    const { name } = user;
    // age is not extracted
  • Renaming

    Use shorter or clearer variable names with renaming.

    const { name: userName, age: userAge } = user;
  • Nested objects

    Destructure nested objects by continuing the pattern.

    const user = { profile: { name: "Alice" } };
    const { profile: { name } } = user;
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Destructuring
Chapter 05 · Page 43
Beginner

JavaScript Destructuring

(continued)

Array Destructuring

  • Position-based extraction

    Extract array elements into separate variables by position.

    const colors = ["red", "green", "blue"];
    const [first, second, third] = colors;
    console.log(first); // "red"
  • Skipping elements

    Skip elements by leaving the position empty.

    const [first, , third] = colors;
    // second is not assigned
  • Rest syntax

    Use rest syntax to capture remaining elements.

    const [first, ...rest] = colors;
    // first = "red", rest = ["green", "blue"]
  • Nested arrays

    Destructure nested arrays the same way as nested objects.

    const matrix = [[1, 2], [3, 4]];
    const [[a, b], [c, d]] = matrix;
  • Swapping variables

    Swap variables without a temporary variable.

    let x = 1, y = 2;
    [x, y] = [y, x]; // x = 2, y = 1
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Destructuring
Chapter 05 · Page 44
Beginner

JavaScript Destructuring

(continued)

Default Values

  • Basic defaults

    Provide default values for properties that might be missing.

    const { name = "Guest", email = "no-email" } = {};
    console.log(name); // "Guest"
  • Works with arrays too

    Defaults work with both objects and arrays.

    const [first = "a", second = "b"] = [];
    // first = "a", second = "b"
  • Undefined only

    Defaults are used only if the value is undefined, not falsy.

    const { count = 0 } = { count: false };
    // count = false, not 0
  • Defaults in parameters

    Use defaults with function parameters for required values.

    function greet({ name = "Guest" } = {}) {
      console.log(`Hello ${name}`);
    }
    greet(); // "Hello Guest"
  • Renaming plus defaults

    Combine renaming and defaults in one destructuring expression.

    const { name: userName = "Anonymous", age: userAge = 0 } = {};
    console.log(userName); // "Anonymous"
    console.log(userAge);  // 0
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Destructuring
Chapter 05 · Page 45
Beginner

JavaScript Destructuring

(continued)

Function Parameters

  • Destructured object params

    Destructure objects directly in function parameters.

    function displayUser({ name, age }) {
      console.log(`${name} is ${age}`);
    }
    displayUser({ name: "Alice", age: 30 });
  • Destructured array params

    Destructure arrays in function parameters the same way.

    function sum([a, b]) {
      return a + b;
    }
    sum([1, 2]); // 3
  • Default params

    Use default parameters together with destructuring.

    function greet({ greeting = "Hello" } = {}) {
      console.log(greeting);
    }
    greet(); // "Hello"
  • Self-documenting

    This pattern makes function signatures self-documenting.

  • Shape validation

    Destructuring in parameters forces the caller's data to have the expected shape.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Destructuring
Chapter 05 · Page 46
Beginner

JavaScript Destructuring

(continued)

Advanced Patterns

  • Computed property names

    Extract a property using a dynamic key with computed property names.

    const key = "name";
    const { [key]: value } = { name: "Alice" };
  • Collect remaining properties

    Extract named properties and collect the rest into a new object.

    const { name, ...rest } = { name: "Alice", age: 30, city: "NYC" };
    // rest = { age: 30, city: "NYC" }
  • Rename plus defaults

    Rename multiple properties and set defaults in the same pattern.

    const { name: n = "Guest", age: a = 0 } = user;
  • Deeply nested aliases

    Destructure deeply nested paths with renaming in a single expression.

    const {
      profile: {
        contact: { email }
      }
    } = user;
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Destructuring
Chapter 05 · Page 47
Beginner

JavaScript Destructuring

(FAQ)

FAQ

Use the colon syntax: const { name: firstName } = user assigns the name property to a variable called firstName. This lets you avoid naming conflicts or clarify intent without modifying the original object.

Yes — chain the syntax: const { address: { city } } = user extracts city from a nested object. Be careful with deep nesting. It throws if an intermediate property is null or undefined.

Array destructuring uses square brackets and assigns by position, like const [first, second] = arr. Object destructuring uses curly braces and assigns by property name instead. Use array destructuring when order matters, object destructuring when keys matter.

Leave a blank space with a comma: const [, second, , fourth] = arr skips the first and third elements. Each comma advances the position without creating a variable.

This usually means there's a typo in the property name — destructuring is case-sensitive and must match the exact key. Use default values, like const { count = 0 } = obj, to guard against missing or undefined properties.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Destructuring
Chapter 05 · Page 48
Beginner

JavaScript Destructuring

(In Practice)
In Practice

Extracting Config from an API Response

Nested destructuring, renaming, and defaults pull exactly the fields needed from a server response in one expression.

  1. 01The outer pattern reaches into data, then into user and settings, without intermediate variables.
  2. 02name: userName renames the nested property while role = 'guest' supplies a fallback if it's missing.
  3. 03settings: { theme = 'light' } = {} guards against settings itself being undefined.
  4. 04...meta collects every top-level property not already destructured, here just status.
const response = {
  status: 200,
  data: {
    user: { id: 7, name: 'Priya', role: 'admin' },
    settings: { theme: 'dark' }
  }
};

const {
  data: {
    user: { name: userName, role = 'guest' },
    settings: { theme = 'light' } = {}
  },
  ...meta
} = response;

console.log(userName, role, theme); // "Priya" "admin" "dark"
console.log(meta); // { status: 200 }
Takeaway

Nested destructuring with renaming and defaults pulls exactly the fields you need in one expression.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript DOM Manipulation
Chapter 06 · Page 49
Beginner

JavaScript DOM Manipulation

Select, edit, style, and create DOM elements with vanilla JavaScript and handle user events.

TL;DR

  1. 01Select elements with querySelector() and getElementById() before reading or editing them.
  2. 02Edit content with textContent, and toggle styles with classList.
  3. 03Attach addEventListener() to respond to clicks and other user actions.

Tips

  1. 01Use textContent instead of innerHTML when inserting user-provided text, since it prevents HTML injection and runs faster.
  2. 02Attach one addEventListener() call to a parent element instead of many on children, so new elements work automatically through delegation.

Warnings

  1. 01Adding many elements one by one causes slow page reflows, so use a DocumentFragment for batch inserts in large lists.
  2. 02Setting innerHTML with untrusted or user-supplied content opens the door to script injection, so sanitize it or use textContent instead.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript DOM Manipulation
Chapter 06 · Page 50
Beginner

JavaScript DOM Manipulation

(continued)

Selecting Elements

  • getElementById()

    Faster than querySelector, but only matches elements by their unique ID.

    const title = document.getElementById('title');
  • querySelector()

    Finds the first element that matches any valid CSS selector.

    const btn = document.querySelector('.btn');
  • querySelectorAll()

    Gets every matching element as a static NodeList for looping.

    const els = document.querySelectorAll('.item');
  • NodeList methods

    NodeLists support forEach, but use Array.from() for full array methods.

    Array.from(items).map(el => el.textContent);
  • Cache selections

    Cache repeated selections in a variable to keep your code fast.

    const btn = document.querySelector('.btn');
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript DOM Manipulation
Chapter 06 · Page 51
Beginner

JavaScript DOM Manipulation

(continued)

Editing Content

  • textContent

    Escapes everything you assign to it, unlike innerHTML, which parses markup.

    title.textContent = 'New Title';
  • innerHTML

    Inserts HTML markup, but only with trusted content since it executes scripts.

    title.innerHTML = '<em>New Title</em>';
  • Reading text

    Read element text the same way you set it, using the same properties.

    console.log(title.textContent);
  • insertAdjacentHTML()

    Inserts markup at a specific position without replacing existing content.

    list.insertAdjacentHTML('beforeend', html);
  • Template literals

    Use template literals to build dynamic strings before assigning them.

    title.innerHTML = `<em>${name}</em> logged in`;
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript DOM Manipulation
Chapter 06 · Page 52
Beginner

JavaScript DOM Manipulation

(continued)

Styling Elements

  • Inline styles

    Work well for one-off changes, but classList methods scale better overall.

    btn.style.backgroundColor = 'tomato';
  • classList.add()

    Adds a CSS class to the element for cleaner styling control.

    btn.classList.add('active');
  • classList.toggle()

    Toggles a class on and off with a single method call.

    btn.classList.toggle('highlight');
  • classList.remove()

    Removes a class when the state changes back to normal.

    btn.classList.remove('active');
  • classList.contains()

    Checks whether an element currently has a given class applied.

    btn.classList.contains('active');
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript DOM Manipulation
Chapter 06 · Page 53
Beginner

JavaScript DOM Manipulation

(continued)

Creating and Removing

  • createElement()

    Builds a new element that isn't yet attached to the DOM.

    const newDiv = document.createElement('div');
    newDiv.textContent = 'Hello!';
  • appendChild() / append()

    Inserts the new element into the DOM; append() also accepts strings and multiple arguments.

    document.body.appendChild(newDiv);
  • remove()

    Removes an element from the DOM by calling remove() on it directly.

    newDiv.remove();
  • insertBefore() / prepend()

    Use these to control the exact position where new elements land.

    list.prepend(newItem); // inserts first
  • DocumentFragment

    Batches multiple appends into one operation, avoiding repeated page reflows.

    const frag = document.createDocumentFragment();
    items.forEach(i => frag.append(i));
    list.append(frag);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript DOM Manipulation
Chapter 06 · Page 54
Beginner

JavaScript DOM Manipulation

(continued)

Traversing the DOM

  • parentElement

    Accesses the direct parent of the current element, or null.

    const parent = btn.parentElement;
  • children

    Accesses all direct children of an element as a live HTMLCollection.

    const items = list.children; // live collection
  • Sibling properties

    Move to the next or previous sibling at the same level.

    const next = el.nextElementSibling;
    const prev = el.previousElementSibling;
  • closest()

    Finds the nearest matching ancestor starting from any element, or null.

    const card = btn.closest('.card');
  • contains()

    Checks whether one element is a descendant of another, anywhere in the tree.

    document.body.contains(btn); // true or false
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript DOM Manipulation
Chapter 06 · Page 55
Beginner

JavaScript DOM Manipulation

(FAQ)

FAQ

getElementById() is slightly faster and only searches by ID. querySelector() accepts any CSS selector, like class, tag, or attribute, making it more flexible. Use getElementById() when you have an ID, querySelector() for everything else.

Use element.classList.add('myClass'), classList.remove('myClass'), or classList.toggle('myClass') for conditional toggling. Avoid directly manipulating element.className as a string, since that overwrites all existing classes.

Use document.createElement('tag') to create the element, set its properties, then append it with parentElement.appendChild(newElement) or parentElement.append(newElement). The append method also accepts plain strings and multiple arguments, making it more versatile.

Event listeners attached with addEventListener only apply to elements that exist at the time of binding, not dynamically added ones. Use event delegation instead: attach the listener to a stable parent element and check event.target inside the handler.

Use getAttribute('src') and setAttribute('src', value) to work with the raw HTML attribute string. Access the property directly, like element.src, to get the resolved, live value instead. The property is usually more convenient, but attributes are necessary for custom or non-reflected attributes like data-* or aria-*.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript DOM Manipulation
Chapter 06 · Page 56
Beginner

JavaScript DOM Manipulation

(In Practice)
In Practice

Adding Todo Items with Event Delegation

Creates new list items dynamically and uses one delegated click listener on the parent to handle removal for every item.

  1. 01addTodo() builds a new li with createElement, then append() attaches a remove button inside it.
  2. 02One click listener on the parent list handles every item — event delegation means new items work without extra listeners.
  3. 03event.target checks which element was actually clicked, since the listener fires from the parent.
  4. 04closest('li') walks up from the clicked button to find the row that needs to be removed.
const list = document.querySelector('#todo-list');

function addTodo(text) {
  const li = document.createElement('li');
  li.textContent = text;
  li.classList.add('todo-item');

  const removeBtn = document.createElement('button');
  removeBtn.textContent = 'Remove';
  removeBtn.classList.add('remove-btn');

  li.append(removeBtn);
  list.append(li);
}

list.addEventListener('click', (event) => {
  if (event.target.classList.contains('remove-btn')) {
    event.target.closest('li').remove();
  }
});

addTodo('Buy groceries');
addTodo('Walk the dog');
// clicking any "Remove" button, even on future items, removes its row
Takeaway

One delegated listener on a parent element handles clicks on any child, present or future, without rebinding.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Loops
Chapter 07 · Page 57
Beginner

JavaScript Loops

Pick the right loop in JavaScript with for, while, for-of, for-in, and array methods.

TL;DR

  1. 01Use for and while loops for full counter control.
  2. 02Use for...of for array values and for...in for object keys.
  3. 03Use map() and filter() array methods for transformations.

Tips

  1. 01Prefer array methods like map() and filter() over for loops because they make your data transformations more readable.
  2. 02Use for...of instead of for...in on arrays because for...in iterates keys as strings and inherits prototype properties.

Warnings

  1. 01Avoid modifying an array with splice() or push() while looping, since this skips elements and causes subtle index bugs.
  2. 02Using await inside a forEach callback silently fails to pause, because forEach ignores returned promises and runs callbacks concurrently.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Loops
Chapter 07 · Page 58
Beginner

JavaScript Loops

(continued)

For and While

  • for

    Runs a block of code a set number of times using an initialized counter.

    for (let i = 0; i < 5; i++) {
      console.log(i);
    }
  • while

    Repeatedly executes a block of code as long as a specified condition remains true.

    let n = 0;
    while (n < 3) {
      console.log(n);
      n++;
    }
  • do...while

    Runs a block of code once before checking if the loop condition is true.

    let i = 0;
    do {
      console.log(i);
      i++;
    } while (i < 3);
  • break / continue

    Use break to exit a loop immediately and continue to skip the current iteration.

    for (let i = 0; i < 5; i++) {
      if (i === 2) continue;
      if (i === 4) break;
      console.log(i);
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Loops
Chapter 07 · Page 59
Beginner

JavaScript Loops

(continued)

For-of for Arrays

  • for...of

    Iterates directly over iterable values like array elements without manual index management.

    const nums = [10, 20, 30];
    for (const n of nums) {
      console.log(n);
    }
  • Iterable objects

    Works natively on strings, sets, maps, and other built-in iterable structures.

    for (const char of "Hi") {
      console.log(char);
    }
  • Destructuring

    Unpacks properties directly within the loop declaration for cleaner object access.

    const users = [{ name: "Ada" }, { name: "Bob" }];
    for (const { name } of users) {
      console.log(name);
    }
  • entries()

    Returns index-value pairs to retrieve the loop counter alongside the element.

    const items = ["a", "b"];
    for (const [index, val] of items.entries()) {
      console.log(index, val);
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Loops
Chapter 07 · Page 60
Beginner

JavaScript Loops

(continued)

For-in for Objects

  • for...in

    Iterates over the enumerable string property keys of an object.

    const user = { name: "Ada", age: 30 };
    for (const key in user) {
      console.log(`${key}: ${user[key]}`);
    }
  • hasOwnProperty()

    Filters out inherited properties to iterate only the object's own direct properties.

    for (const key in user) {
      if (user.hasOwnProperty(key)) {
        console.log(key);
      }
    }
  • Object.entries()

    Converts object properties into key-value arrays for cleaner, modern iteration.

    const user = { name: "Ada", age: 30 };
    for (const [key, val] of Object.entries(user)) {
      console.log(`${key}: ${val}`);
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Loops
Chapter 07 · Page 61
Beginner

JavaScript Loops

(continued)

Async Loops

  • for...of with await

    Executes async tasks sequentially, pausing the loop for each promise to resolve.

    for (const id of ids) {
      const res = await fetchItem(id);
      console.log(res);
    }
  • forEach warning

    Avoid await in forEach; it ignores returned promises and fires them concurrently.

    // Broken: will not wait for save to complete
    items.forEach(async item => {
      await save(item);
    });
  • Promise.all()

    Runs all async operations in parallel by mapping items to an array of promises.

    const apiCall = id => fetchItem(id);
    const results = await Promise.all(
      ids.map(apiCall)
    );
  • for await...of

    Iterates over async iterables, waiting for each value to resolve sequentially.

    for await (const chunk of readStream()) {
      console.log(chunk);
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Loops
Chapter 07 · Page 62
Beginner

JavaScript Loops

(continued)

Nested and Control

  • Nested loops

    Runs a loop inside another loop; plain break only escapes the inner loop.

    for (let i = 0; i < 2; i++) {
      for (let j = 0; j < 3; j++) {
        console.log(`${i},${j}`);
      }
    }
  • Labeled break

    Exits multiple levels of nesting at once by referencing a statement label.

    outer: for (let i = 0; i < 3; i++) {
      for (let j = 0; j < 3; j++) {
        if (i === 1) break outer;
      }
    }
  • Loop performance

    Cache array length before the loop to avoid querying it on every iteration.

    const len = items.length;
    for (let i = 0; i < len; i++) {
      console.log(items[i]);
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Loops
Chapter 07 · Page 63
Beginner

JavaScript Loops

(FAQ)

FAQ

The for...of loop iterates over iterable values like arrays, strings, Set, or Map. In contrast, for...in iterates over an object's enumerable property keys as strings. Use for...of when you want element values and for...in when you need to walk property keys.

The await keyword works correctly inside for, for...of, and while loops, running each iteration sequentially. Avoid using await inside forEach because it ignores returned promises and runs callbacks concurrently without waiting. Use a for...of loop instead.

Label the outer loop as outer:. Call break outer inside the inner loop to exit both levels at once. Alternatively, extract the nested loops into a separate function and use a return statement to exit early.

The for...in loop enumerates all inherited enumerable properties in addition to direct properties. Use Object.keys(obj) to retrieve only the object's own enumerable keys as an array. Alternatively, add an hasOwnProperty() guard check inside the loop.

Prefer map() when producing a new array of the same length with transformed values, and filter() when selecting a subset. Both express intent clearly. Reach for a for or for...of loop when you need to break early or accumulate a non-array result.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Loops
Chapter 07 · Page 64
Beginner

JavaScript Loops

(In Practice)
In Practice

Processing Shopping Cart Items

Iterates through store inventory to calculate cart totals and build order summaries while skipping out of stock items.

  1. 01Declare an inventory array and initialize variables to track the final total and name list.
  2. 02Iterate through each inventory item using a sequential for...of loop.
  3. 03Skip items that are out of stock using a continue statement to prevent incorrect calculations.
  4. 04Accumulate the price of in-stock items and record their names to finalize the order summary.
const items = [
  { name: "Book", price: 15, stock: 4 },
  { name: "Pen", price: 2, stock: 0 },
  { name: "Laptop", price: 800, stock: 2 }
];

let cartTotal = 0;
const orderSummary = [];

for (const item of items) {
  if (item.stock === 0) continue;
  cartTotal += item.price;
  orderSummary.push(item.name);
}
Takeaway

Use continue to skip invalid or out-of-stock data without breaking the entire loop execution.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Object Manipulation
Chapter 08 · Page 65
Beginner

JavaScript Object Manipulation

Create, clone, merge, and transform JavaScript objects with modern syntax and practical patterns.

TL;DR

  1. 01Create objects with literals, classes, or Object.create for different needs.
  2. 02Clone shallow with spread or deep with structuredClone.
  3. 03Merge objects easily using spread syntax or Object.assign.

Tips

  1. 01Use structuredClone() instead of JSON.parse(JSON.stringify(obj)) to deep-clone, since it handles dates, maps, and other types correctly.
  2. 02Use Object.hasOwn(obj, 'key') instead of hasOwnProperty() directly, since it works safely even on objects created with Object.create(null).

Warnings

  1. 01Spread and Object.assign() only do shallow copies, so changes to nested objects in the copy will still affect the original.
  2. 02Checking a property with truthy logic like if (obj.key) misfires when the value is legitimately 0 or false.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Object Manipulation
Chapter 08 · Page 66
Beginner

JavaScript Object Manipulation

(continued)

Creating Objects

  • Object Literal

    Builds an object directly from comma-separated key-value pairs in one line.

    const user = { name: 'Ava', age: 28 };
  • class

    Defines a reusable blueprint with shared methods and a constructor.

    class User {
      constructor(name) { this.name = name; }
    }
  • Object.create()

    Creates an object that inherits directly from a given prototype object.

    const proto = { greet() { return 'Hi!'; } };
    const user = Object.create(proto);
  • Computed Property

    Sets a dynamic key name using bracket syntax inside an object literal.

    const key = 'role';
    const user = { [key]: 'admin' };
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Object Manipulation
Chapter 08 · Page 67
Beginner

JavaScript Object Manipulation

(continued)

Access and Modify

  • Dot Notation

    Reads or writes a property using a fixed, known key name.

    console.log(user.name); // 'Ava'
  • Bracket Notation

    Reads a property using a variable or a name with special characters.

    console.log(user['role']); // dynamic key ok
  • Optional Chaining

    Safely reads a deeply nested property without throwing if it's missing.

    console.log(user?.address?.city);
  • Nullish Coalescing

    Provides a fallback value only when the left side is null or undefined.

    console.log(user.phone ?? 'N/A');
  • delete

    Removes a property from an object entirely, including its key.

    delete user.temp; // removes the property
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Object Manipulation
Chapter 08 · Page 68
Beginner

JavaScript Object Manipulation

(continued)

Enumerate Properties

  • Object.keys()

    Returns an array of an object's own enumerable property names.

    Object.keys({ a: 1, b: 2 }); // ['a', 'b']
  • Object.values()

    Returns an array of just the object's own property values.

    Object.values({ a: 1, b: 2 }); // [1, 2]
  • Object.entries()

    Returns an array of [key, value] pairs for looping or transforms.

    Object.entries({ a: 1 }); // [['a', 1]]
  • for...in

    Loops over enumerable keys, including any inherited from the prototype.

    for (const key in user) {
      console.log(key);
    }
  • Object.hasOwn()

    Checks whether an object owns a given key, ignoring inherited ones.

    Object.hasOwn(user, 'name'); // true
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Object Manipulation
Chapter 08 · Page 69
Beginner

JavaScript Object Manipulation

(continued)

Cloning

  • Spread

    Creates a shallow copy with every enumerable own property copied over.

    const copy = { ...original };
  • Object.assign()

    Copies properties into a new target object; also works for merging.

    const copy = Object.assign({}, original);
  • structuredClone()

    Deep-clones nested objects, Dates, Maps, and Sets without shared references.

    const deep = structuredClone(original);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Object Manipulation
Chapter 08 · Page 70
Beginner

JavaScript Object Manipulation

(continued)

Merge and Transform

  • Spread Merge

    Merges objects into a new one; later keys overwrite earlier matches.

    const merged = { ...base, ...extra };
  • Object.assign(target, source)

    Merges source properties directly into an existing target object in place.

    Object.assign(base, extra); // mutates base
  • Object.fromEntries()

    Builds an object from an array of [key, value] pairs for fast lookups.

    const map = Object.fromEntries(
      users.map(u => [u.id, u])
    );
  • entries() + map()

    Converts an object back into an array to transform or filter it.

    Object.entries(user).map(([k, v]) => `${k}:${v}`);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Object Manipulation
Chapter 08 · Page 71
Beginner

JavaScript Object Manipulation

(FAQ)

FAQ

Use structuredClone(obj), which natively handles Dates, Maps, Sets, RegExp, and typed arrays. JSON.parse(JSON.stringify()) silently corrupts Dates into strings and drops undefined values entirely.

Both produce a shallow merge, but Object.assign() mutates the target in place, while spread ({...a, ...b}) returns a new object. Prefer spread to avoid modifying an existing object by accident.

Use Object.entries(obj) with for...of to destructure each pair: for (const [key, val] of Object.entries(obj)). Use Object.keys() or Object.values() when you only need one side.

Use computed property syntax directly in the literal: { [variableName]: value }. This is cleaner than creating the object first and then assigning with bracket notation afterward.

Use Object.hasOwn(obj, 'key') for own properties (ES2022), or the in operator to include inherited ones. Avoid relying on truthiness like if (obj.key), since a property can legitimately hold 0, false, or null.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Object Manipulation
Chapter 08 · Page 72
Beginner

JavaScript Object Manipulation

(In Practice)
In Practice

Merge Settings and Build a Lookup

Merges user setting overrides onto defaults, then builds an id-keyed lookup map with Object.fromEntries().

  1. 01Spread merges overrides on top of defaults, so later keys always win.
  2. 02Object.fromEntries() turns the users array into an id-keyed lookup map.
  3. 03Nullish coalescing (??) supplies a fallback only when a value is missing.
  4. 04Optional chaining (?.) reads byId[9] safely even though that id doesn't exist.
const defaults = { theme: 'light', notifications: true };
const overrides = { theme: 'dark', fontSize: 14 };

const settings = { ...defaults, ...overrides };

const users = [
  { id: 1, name: 'Ava', role: 'admin' },
  { id: 2, name: 'Noah', role: 'editor' },
  { id: 3, name: 'Mia', role: 'viewer' },
];

const byId = Object.fromEntries(users.map(u => [u.id, u]));

console.log(settings.theme);          // 'dark'
console.log(settings.fontSize ?? 12); // 14
console.log(byId[2]?.name);           // 'Noah'
console.log(byId[9]?.name ?? 'N/A');  // 'N/A'
Takeaway

Spread later objects last so their keys win, and use Object.fromEntries() for instant id-based lookups.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Storage
Chapter 09 · Page 73
Beginner

JavaScript Storage

Use localStorage and sessionStorage to persist data in the browser across sessions and refreshes.

TL;DR

  1. 01Use localStorage to save data that persists across browser sessions.
  2. 02Use sessionStorage for temporary data cleared when the tab closes.
  3. 03Store only strings by converting objects to JSON first.

Tips

  1. 01Use localStorage for user preferences and sessionStorage for temporary state, then sync between tabs using storage events.
  2. 02Wrap JSON.parse() calls in a try/catch block because corrupted or manually edited storage data throws exceptions.

Warnings

  1. 01Avoid storing sensitive data like passwords or tokens in localStorage because it is vulnerable to cross-site scripting attacks.
  2. 02Saving an object directly without JSON.stringify() stores the useless string [object Object] instead of your data.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Storage
Chapter 09 · Page 74
Beginner

JavaScript Storage

(continued)

localStorage Basics

  • localStorage

    A browser storage object that persists key-value data indefinitely with no expiration date.

    localStorage.setItem("username", "Alice");
    const name = localStorage.getItem("username");
  • removeItem()

    Deletes a specific key-value pair from storage by providing the key name.

    localStorage.removeItem("username");
  • clear()

    Wipes all stored key-value data for the current domain origin at once.

    localStorage.clear();
  • in operator

    Checks if a specific storage key exists in the storage object dictionary.

    if ("username" in localStorage) {
      console.log("Key exists!");
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Storage
Chapter 09 · Page 75
Beginner

JavaScript Storage

(continued)

sessionStorage

  • sessionStorage

    A storage object that maintains key-value data for the duration of the page session.

    sessionStorage.setItem("tabId", "12345");
    const id = sessionStorage.getItem("tabId");
  • Tab isolation

    Maintains separate storage instances for each open browser tab, even on the same origin.

    // A new window starts a fresh storage instance
  • Identical API

    Shares the same storage interface, methods, and behaviors as localStorage.

    sessionStorage.setItem("key", "val");
    sessionStorage.removeItem("key");
    sessionStorage.clear();
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Storage
Chapter 09 · Page 76
Beginner

JavaScript Storage

(continued)

Storing Objects

  • JSON.stringify()

    Serializes objects or arrays into strings before saving them to browser storage.

    const user = { name: "Alice", age: 30 };
    localStorage.setItem("user", JSON.stringify(user));
  • JSON.parse()

    Deserializes stored JSON strings back into usable JavaScript objects or arrays.

    const raw = localStorage.getItem("user");
    const user = JSON.parse(raw);
    console.log(user.name); // "Alice"
  • Error handling

    Wraps JSON parsing in try-catch blocks to prevent crashes on invalid data formats.

    try {
      const user = JSON.parse(localStorage.getItem("user"));
    } catch (e) {
      console.error("Invalid JSON stored");
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Storage
Chapter 09 · Page 77
Beginner

JavaScript Storage

(continued)

Storage Events

  • storage event

    Listens for storage changes on the window object across different origin tabs.

    window.addEventListener("storage", e => {
      console.log(`${e.key} changed to ${e.newValue}`);
    });
  • Cross-tab sync

    Notifies other open tabs on the same origin immediately when storage updates.

    // Tab A writes to storage
    localStorage.setItem("theme", "dark");
    
    // Tab B receives storage event automatically
  • StorageEvent object

    Exposes modified keys, new values, old values, and the target storage area.

    window.addEventListener("storage", e => {
      if (e.key === "theme") {
        applyTheme(e.newValue);
      }
    });
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Storage
Chapter 09 · Page 78
Beginner

JavaScript Storage

(continued)

Best Practices

  • QuotaExceededError

    Catches browser storage limit exceptions to avoid crashing applications when disk space runs out.

    try {
      localStorage.setItem("key", largeData);
    } catch (e) {
      if (e.name === "QuotaExceededError") {
        console.warn("Storage limit exceeded!");
      }
    }
  • Namespacing

    Prefixes storage keys to prevent overlap conflicts with other third-party scripts.

    localStorage.setItem("myApp_theme", "dark");
    localStorage.setItem("myApp_lang", "en");
  • Security warnings

    Avoids storing sensitive authentication tokens, passwords, or personal data in plaintext storage.

    // Avoid storing JWTs in localStorage
    // Secure: use HTTP-only, secure cookies instead
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Storage
Chapter 09 · Page 79
Beginner

JavaScript Storage

(FAQ)

FAQ

The localStorage object persists data indefinitely across browser sessions and tabs. In contrast, sessionStorage is cleared automatically when the tab or window closes. Use localStorage for user preferences and sessionStorage for temporary form state.

Convert the object to a string using JSON.stringify() before saving it with localStorage.setItem(). Read it back by parsing the string with JSON.parse(). Skipping this serialization step mistakenly stores the string [object Object].

Listen for the storage event on the window object. This event fires in all other tabs when localStorage is updated. It provides the modified key, oldValue, and newValue to sync your frontend.

The localStorage.setItem() method throws a QuotaExceededError when storage limit is reached. This limit is typically five megabytes. Always wrap write operations in try/catch blocks to handle storage failures gracefully.

Call localStorage.removeItem('key') to delete a specific item. Alternatively, use localStorage.clear() to wipe all stored key-value pairs for the origin. Use clear() with caution as it clears data from all scripts.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Storage
Chapter 09 · Page 80
Beginner

JavaScript Storage

(In Practice)
In Practice

Managing User Preference Storage

Saves and loads user interface preferences using JSON serialization while handling storage quotas and parsing errors.

  1. 01Create a preferences object containing the user's selected theme and font size.
  2. 02Serialize the preferences object to a JSON string and store it safely in localStorage.
  3. 03Catch any storage quota errors that might arise if the browser storage is full.
  4. 04Retrieve and parse the stored JSON string back into a JavaScript object when the page loads.
  5. 05Fallback to default values if preferences are missing or the string contains invalid data.
function savePreferences(theme, fontSize) { 
  const prefs = { theme, fontSize };
  try {
    const serialized = JSON.stringify(prefs);
    localStorage.setItem("user_prefs", serialized);
  } catch (e) {
    console.error("Save failed", e);
  }
}

function loadPreferences() {
  const raw = localStorage.getItem("user_prefs");
  if (!raw) return { theme: "light", fontSize: 14 };
  try {
    return JSON.parse(raw);
  } catch (e) {
    return { theme: "light", fontSize: 14 };
  }
}
Takeaway

Always serialize objects before storing them and use try-catch to safeguard against corrupted data or full storage.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript String Methods
Chapter 10 · Page 81
Beginner

JavaScript String Methods

Master string manipulation with substring, slice, replace, split, and common text operations.

TL;DR

  1. 01Use slice() and substring() to extract portions of strings.
  2. 02Use replace() and replaceAll() to substitute text inside strings.
  3. 03Use split() and join() to convert between strings and arrays.

Tips

  1. 01Use includes() instead of indexOf() !== -1 to write cleaner, more readable boolean search checks on strings.
  2. 02Use localeCompare() instead of comparison operators when sorting strings containing accented characters to ensure correct alphabetical ordering.

Warnings

  1. 01Avoid using the deprecated substr() method because it is not supported in some modern environments and libraries.
  2. 02Remember that JavaScript strings are immutable, meaning methods like trim() and replace() always return new string values.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript String Methods
Chapter 10 · Page 82
Beginner

JavaScript String Methods

(continued)

Extracting Substrings

  • slice()

    Extracts a section of a string and returns it as a new string.

    const text = "Hello World";
    const res = text.slice(0, 5); // "Hello"
    const word = text.slice(-5);  // "World"
  • substring()

    Extracts characters between two indices, treating negative index numbers as zero.

    const text = "Hello";
    const res = text.substring(1, 4); // "ell"
  • substr()

    Extracts a substring starting at an index for a specified character length.

    const text = "Hello";
    const res = text.substr(1, 3); // "ell"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript String Methods
Chapter 10 · Page 83
Beginner

JavaScript String Methods

(continued)

Finding and Checking

  • indexOf()

    Returns the index of the first occurrence of a specified substring.

    const text = "hello world";
    text.indexOf("world"); // 6
    text.indexOf("xyz");   // -1
  • includes()

    Performs a case-sensitive search to determine if a substring exists.

    const text = "hello world";
    text.includes("world"); // true
  • startsWith()

    Checks if a string begins with the characters of a specified string.

    const text = "hello";
    text.startsWith("he"); // true
  • search()

    Executes a regular expression search and returns the first matching index.

    const text = "hello123";
    text.search(/\d+/); // 5
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript String Methods
Chapter 10 · Page 84
Beginner

JavaScript String Methods

(continued)

Replace and Transform

  • replace()

    Replaces the first match of a substring or regular expression pattern.

    const text = "hello world";
    text.replace("world", "there"); // "hello there"
  • replaceAll()

    Replaces all occurrences of a literal substring or global regex pattern.

    const text = "hello hello";
    text.replaceAll("hello", "hi"); // "hi hi"
  • Case conversion

    Transforms all characters in a string to uppercase or lowercase forms.

    const text = "Hello";
    text.toUpperCase(); // "HELLO"
    text.toLowerCase(); // "hello"
  • Replace callback

    Uses a replacement function to compute custom replacements for each match.

    const text = "hello world";
    const title = text.replace(
      /\b\w/g,
      ch => ch.toUpperCase()
    );
    // "Hello World"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript String Methods
Chapter 10 · Page 85
Beginner

JavaScript String Methods

(continued)

Split and Join

  • split()

    Splits a string into an array of substrings using a separator.

    const text = "a,b,c";
    text.split(","); // ["a", "b", "c"]
  • join()

    Concatenates all elements of an array into a single string separator.

    ["a", "b", "c"].join(","); // "a,b,c"
  • split limit

    Truncates the resulting array to a specified maximum number of elements.

    const text = "a,b,c,d";
    text.split(",", 2); // ["a", "b"]
  • regex split

    Splits a string using a regular expression to match multiple separators.

    const text = "one, two; three";
    text.split(/[,;]\s*/); // ["one", "two", "three"]
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript String Methods
Chapter 10 · Page 86
Beginner

JavaScript String Methods

(continued)

Trimming and Padding

  • trim()

    Removes whitespace characters from both the beginning and end of strings.

    const text = "  hello  ";
    text.trim(); // "hello"
  • trimStart()

    Removes whitespace characters only from the beginning of a string.

    const text = "  hello";
    text.trimStart(); // "hello"
  • padStart()

    Pads the current string from the start with a given fill character.

    const text = "5";
    text.padStart(3, "0"); // "005"
  • repeat()

    Returns a new string containing the specified number of concatenated copies.

    const text = "-";
    text.repeat(10); // "----------"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript String Methods
Chapter 10 · Page 87
Beginner

JavaScript String Methods

(FAQ)

FAQ

Both methods extract parts of strings using start and end indices. However, slice() supports negative indices to count from the end of the string. The substring() method treats negative values as zero. Prefer slice() for its flexibility.

Use replaceAll('old', 'new') to replace every match of a literal substring. Alternatively, use a regular expression with the global flag like replace(/pattern/g, 'new'). The standard replace() method only replaces the first occurrence.

Chain the split() and join() methods to transform the text. For example, 'hello world'.split(' ') creates an array of words. Rejoin them using .join('-') to produce the dashed string 'hello-world'.

Use padStart(targetLength, padChar) to insert characters from the left. For example, '7'.padStart(3, '0') outputs '007'. To pad from the right, use padEnd() instead.

These methods perform clean boolean checks to verify string boundaries. They return true if the string starts or ends with the target substring. Both methods accept an optional index to adjust the search boundary.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript String Methods
Chapter 10 · Page 88
Beginner

JavaScript String Methods

(In Practice)
In Practice

Formatting and Normalizing User Names

Cleans up messy text inputs by trimming excess whitespace and capitalizing the first letter of each name word.

  1. 01Trim leading and trailing whitespace from the raw user input.
  2. 02Split the cleaned string into an array of individual words.
  3. 03Map over each word to isolate and capitalize its first character.
  4. 04Convert the remaining characters of each word to lowercase form.
  5. 05Rejoin the capitalized words back into a single space-separated string.
function cleanName(rawName) {
  const trimmed = rawName.trim();
  if (!trimmed) return "";
  const words = trimmed.split(/\s+/);
  const capitalized = words.map(w => {
    const first = w[0].toUpperCase();
    const rest = w.slice(1).toLowerCase();
    return first + rest;
  });
  return capitalized.join(" ");
}
Takeaway

Chain trimming, splitting, mapping, and joining to build powerful and clean text normalization pipelines.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Template Literals
Chapter 11 · Page 89
Beginner

JavaScript Template Literals

Learn template literals, string interpolation, multiline strings, and tagged templates for cleaner code.

TL;DR

  1. 01Use backticks instead of quotes to declare template literals.
  2. 02Insert variables with ${} syntax for clean string interpolation.
  3. 03Write multiline strings directly without escape characters or concatenation.

Tips

  1. 01Prefer template literals over standard string concatenation for readability when assembling strings containing multiple variables.
  2. 02Use a tagged template function to parse and escape user input safely when constructing HTML strings.

Warnings

  1. 01Remember that whitespace and indentation inside template literals are preserved, which can affect your final output layout.
  2. 02Avoid embedding unescaped user inputs into template literals because it introduces severe cross-site scripting vulnerabilities.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Template Literals
Chapter 11 · Page 90
Beginner

JavaScript Template Literals

(continued)

Basic Syntax

  • backticks

    Creates template literals using backticks instead of single or double quotes.

    const text = `Hello, world!`;
  • Multiline strings

    Writes strings across multiple lines without using string concatenation or escape characters.

    const poem = `Roses are red
    Violets are blue`;
  • Line preservation

    Preserves any newlines and indentation inside the template literal body automatically.

    const raw = `
      Indented Line
    `;
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Template Literals
Chapter 11 · Page 91
Beginner

JavaScript Template Literals

(continued)

String Interpolation

  • ${} syntax

    Inserts variables directly into strings without using the concatenation plus operator.

    const name = "Alice";
    const greeting = `Hello, ${name}!`;
  • Expressions

    Evaluates any valid JavaScript expressions inside the interpolation curly braces.

    const a = 5, b = 10;
    const sum = `${a} + ${b} = ${a + b}`;
  • Method calls

    Invokes functions or prototype methods directly inside the string interpolation.

    const title = "main";
    const html = `<h1>${title.toUpperCase()}</h1>`;
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Template Literals
Chapter 11 · Page 92
Beginner

JavaScript Template Literals

(continued)

Multiline HTML

  • HTML templates

    Builds complex multiline HTML string blocks with clean formatting and indentation.

    const html = `
      <div class="card">
        <h2>${title}</h2>
      </div>
    `;
  • trim() utility

    Trims leading and trailing whitespace from the resulting multiline output string.

    const html = `
      <div>${content}</div>
    `.trim();
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Template Literals
Chapter 11 · Page 93
Beginner

JavaScript Template Literals

(continued)

Escaping Characters

  • Backtick escape

    Escapes the backtick character using a backslash inside a template literal.

    const text = `Use \`backticks\` inside`;
  • Special sequences

    Supports standard escape sequences like tabs and newlines within backticks.

    const csv = `Name\tAge\n${name}\t${age}`;
  • Dollar sign escape

    Escapes the dollar sign to prevent it from being parsed as interpolation.

    const price = `Price: \$${amount}`;
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Template Literals
Chapter 11 · Page 94
Beginner

JavaScript Template Literals

(continued)

Tagged Templates

  • Tag function

    Intercepts the template string components and interpolated values using a prefix function.

    function tag(strings, ...values) {
      return strings[0] + values[0];
    }
    const res = tag`Hi ${name}`;
  • Value processing

    Inspects and sanitizes string values before returning the final formatted output.

    function clean(strings, ...values) {
      return values.map(v => String(v).trim());
    }
  • Tagged CSS

    Defines styling or markup templates using tagged template literals.

    const styles = css`
      color: ${color};
      font-size: 14px;
    `;
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Template Literals
Chapter 11 · Page 95
Beginner

JavaScript Template Literals

(FAQ)

FAQ

Yes, template literals preserve actual line breaks. Pressing Enter inside backticks creates a real newline in the string. You do not need to use \n escape sequences anymore.

Place any valid JavaScript expression inside the ${} syntax. For example, you can write mathematical operations or function calls directly. The return value is coerced to a string automatically.

Escape the backtick using a backslash like ``` inside the template body. This prevents the backtick from incorrectly terminating the template string. The backslash is stripped out of the final output.

A tagged template passes the string segments and expression values to a custom function. This function controls how the string is constructed. Tagged templates are common in styling libraries or HTML sanitizers.

No, modern JavaScript engines optimize template literals and string concatenation equally well. There is no performance reason to choose string concatenation over template literals. Use template literals by default.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Template Literals
Chapter 11 · Page 96
Beginner

JavaScript Template Literals

(In Practice)
In Practice

Sanitizing HTML with Tagged Templates

Prevents cross-site scripting attacks by escaping raw user input within a custom tagged template function.

  1. 01Create an escaping utility function to substitute hazardous HTML brackets.
  2. 02Define a tagged template function that iterates over string parts and variables.
  3. 03Sanitize each interpolated value using the escape function before assembly.
  4. 04Reduce and concatenate the parts together to build the secure output string.
  5. 05Invoke the tagged template with potentially unsafe user object values.
function escapeHtml(str) {
  return str
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;");
}

function safeHtml(strings, ...values) {
  return strings.reduce((acc, str, i) => {
    const rawVal = values[i - 1];
    const safe = rawVal ? String(rawVal) : "";
    const val = escapeHtml(safe);
    return acc + val + str;
  });
}

const user = {
  name: "<script>alert(1)</script>",
  role: "Admin"
};

const card = safeHtml`<div class="card">
  <h3>${user.name}</h3>
  <p>Role: ${user.role}</p>
</div>`;
Takeaway

Use tagged templates to automatically sanitize user inputs, preventing cross-site scripting vulnerabilities in your HTML.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Try Catch
Chapter 12 · Page 97
Beginner

JavaScript Try Catch

Handle errors safely with try-catch patterns for async code, error propagation, global handlers, and JSON parsing.

TL;DR

  1. 01Wrap risky code in try blocks to intercept runtime errors.
  2. 02Use try-catch with await to catch rejected promises cleanly.
  3. 03Catch unhandled rejections globally using window error event listeners.

Tips

  1. 01Always include a finally block when managing resources like file handles or database connections to guarantee cleanup.
  2. 02Use the cause option in the Error constructor to preserve the original traceback when wrapping error exceptions.

Warnings

  1. 01Avoid using bare catch blocks that swallow errors silently, as this makes diagnosing application bugs very difficult.
  2. 02Never wrap entire script bodies in a single try-catch statement because it masks syntax errors during load time.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Try Catch
Chapter 12 · Page 98
Beginner

JavaScript Try Catch

(continued)

Async Error Handling

  • try...catch

    Catches errors thrown during asynchronous operations when combined with await.

    async function loadUser(id) {
      try {
        const res = await fetch(`/users/${id}`);
        return await res.json();
      } catch (err) {
        console.error(err.message);
        return null;
      }
    }
  • Multiple awaits

    Groups multiple sequential asynchronous actions into a single error handler block.

    try {
      const user = await getUser();
      const orders = await getOrders(user.id);
      console.log(orders);
    } catch (err) {
      console.error("Chain failed", err);
    }
  • finally

    Guarantees resource cleanup or UI state resets regardless of try-catch outcomes.

    setLoading(true);
    try {
      await saveData(form);
    } catch (err) {
      showError(err.message);
    } finally {
      setLoading(false);
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Try Catch
Chapter 12 · Page 99
Beginner

JavaScript Try Catch

(continued)

Error Propagation

  • throw

    Rethrows a caught error to escalate it up the application call stack.

    function processData(raw) {
      try {
        return JSON.parse(raw);
      } catch (err) {
        console.warn("Parsing failed", err);
        throw err;
      }
    }
  • error cause

    Attaches a low-level error cause when throwing a new high-level wrapper error.

    try {
      await db.query(sql);
    } catch (cause) {
      throw new Error("DB failed", { cause });
    }
  • cause property

    Retrieves the nested origin error object from the cause property during inspection.

    try {
      await loadData();
    } catch (err) {
      console.log(err.cause.message);
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Try Catch
Chapter 12 · Page 100
Beginner

JavaScript Try Catch

(continued)

Global Handlers

  • window.onerror

    Listens for unhandled synchronous execution errors globally across browser page environments.

    window.onerror = (msg, src, line) => {
      console.error(`Error: ${msg} at ${src}:${line}`);
      return true; // intercept
    };
  • unhandledrejection

    Catches any promise rejections that lack a corresponding catch block handler.

    window.addEventListener("unhandledrejection", e => {
      console.error("Unhandled:", e.reason);
      e.preventDefault();
    });
  • uncaughtException

    Listens for terminal exceptions globally in Node.js process environments.

    process.on("uncaughtException", err => {
      console.error("Fatal error occurred:", err);
      process.exit(1);
    });
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Try Catch
Chapter 12 · Page 101
Beginner

JavaScript Try Catch

(continued)

Safe Parsing Patterns

  • JSON.parse()

    Safeguards JSON parsing routines by catching syntax validation failures.

    function parseJSON(str, fallback = null) {
      try {
        return JSON.parse(str);
      } catch {
        return fallback;
      }
    }
  • Optional catch

    Omits the catch block error variable binding when the object is unused.

    try {
      data = JSON.parse(raw);
    } catch {
      data = {};
    }
  • localStorage guard

    Protects localStorage reads which can throw errors in private browser modes.

    function getStored(key) {
      try {
        return JSON.parse(localStorage.getItem(key));
      } catch {
        return null;
      }
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Try Catch
Chapter 12 · Page 102
Beginner

JavaScript Try Catch

(continued)

Inspecting Errors

  • error.stack

    Provides trace details including file locations and execution call history.

    try {
      riskyOperation();
    } catch (err) {
      console.error(err.stack);
    }
  • cause tracing

    Recursively traverses a wrapped error cause chain to resolve the root error.

    try {
      await saveOrder(order);
    } catch (err) {
      let current = err;
      while (current?.cause) {
        current = current.cause;
      }
      console.log("Root:", current.message);
    }
  • AggregateError

    Collects multiple individual promise errors during collective parallel operations.

    try {
      await Promise.any([checkA(), checkB()]);
    } catch (err) {
      err.errors.forEach(e => console.log(e.message));
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Try Catch
Chapter 12 · Page 103
Beginner

JavaScript Try Catch

(FAQ)

FAQ

Use try-catch blocks for unpredictable operations like JSON.parse() or network requests. For values you can verify beforehand using variables or properties, choose conditional null checks instead. Conditional checks are faster and cleaner.

Inspect the caught exception using the instanceof operator inside the catch block. For example, check if (err instanceof TypeError) to handle specific issues. Always rethrow unknown exceptions with throw err to prevent swallowing bugs.

Yes, the finally block is guaranteed to execute even if the try block calls return. It runs right before the function exits. This makes it perfect for resetting loading states and releasing resource handles.

Extend the built-in Error class: class ValidationError extends Error { ... }. Set this.name inside the constructor method. Extending the class ensures you maintain the correct stack trace for debugging.

Yes, wrapping an await statement inside a try-catch block catches promise rejections. This synchronous-like syntax avoids trailing .catch() chains. It simplifies error handling across multiple sequential asynchronous requests.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Try Catch
Chapter 12 · Page 104
Beginner

JavaScript Try Catch

(In Practice)
In Practice

Custom Network Error Wrapping

Wraps network and response parsing exceptions inside a custom error class to maintain context and track causes.

  1. 01Extend the standard error class to declare a custom NetworkError constructor.
  2. 02Perform a fetch request inside a synchronous-like try block.
  3. 03Throw a high-level error if the server response status is not successful.
  4. 04Catch any network or parsing failure inside the catch block handler.
  5. 05Rethrow a custom NetworkError wrapping the original error as the cause.
class NetworkError extends Error {
  constructor(msg, cause) {
    super(msg, { cause });
    this.name = "NetworkError";
  }
}

async function fetchJson(url) {
  try {
    const res = await fetch(url);
    if (!res.ok) throw new Error(res.statusText);
    return await res.json();
  } catch (err) {
    throw new NetworkError("Fetch failed", err);
  }
}
Takeaway

Extend the standard Error class and utilize cause wrapping to propagate debuggable contextual exceptions safely.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async and Await
Chapter 13 · Page 105
Intermediate

JavaScript Async and Await

Handle async code cleanly with async functions, await, error handling, and parallel execution.

TL;DR

  1. 01Mark functions async to make them return promises.
  2. 02Use await to pause and unwrap promise values.
  3. 03Wrap awaited code in try/catch for error handling.

Tips

  1. 01Use Promise.all() for independent async operations to run them in parallel and get faster results.
  2. 02Wrap an async IIFE around top-level code in older environments that don't support top-level await directly.

Warnings

  1. 01Awaiting operations sequentially when they are independent is slower than running them together with Promise.all().
  2. 02An unhandled rejection inside an async function without try/catch crashes Node.js processes by default in current versions.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async and Await
Chapter 13 · Page 106
Intermediate

JavaScript Async and Await

(continued)

Async Functions

  • async keyword

    Adding async to a function changes its return contract to always be a promise.

    async function fetchData() {
      return "data";
    }
    fetchData().then(result => console.log(result));
  • Wrapped return value

    An async function that returns a plain value wraps it in a resolved promise.

  • await inside async

    You can use await only inside a function declared with async.

    async function getData() {
      const response = await fetch("/api/data");
      return response.json();
    }
  • Cleaner syntax

    Async functions are just a cleaner way to work with promises, nothing more.

  • Always a promise

    Every async function returns a promise, even one that never uses await.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async and Await
Chapter 13 · Page 107
Intermediate

JavaScript Async and Await

(continued)

Await Keyword

  • Pause and resolve

    Await pauses the function and hands back the resolved value, nothing more.

    async function getUser(id) {
      const response = await fetch(`/api/users/${id}`);
      const user = await response.json();
      return user;
    }
  • Unwraps promises

    Await unwraps the resolved value from a promise automatically.

  • Scope restriction

    Await only works inside async functions or at a module's top level.

    async function getMultiple() {
      const [a, b] = await Promise.all([
        fetch("/a").then(r => r.json()),
        fetch("/b").then(r => r.json())
      ]);
      return [a, b];
    }
  • Avoid sequential await

    Do not await independent operations one at a time — use Promise.all instead.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async and Await
Chapter 13 · Page 108
Intermediate

JavaScript Async and Await

(continued)

Error Handling

  • try/catch

    A rejected await throws synchronously, so try/catch works like it does with normal exceptions.

    async function fetchData() {
      try {
        const res = await fetch("/data");
        return await res.json();
      } catch (error) {
        console.error("Failed to fetch:", error);
        return null;
      }
    }
  • Catches any await

    The catch block runs when any awaited call inside the try block rejects.

  • finally

    Use finally to run cleanup code regardless of success or failure.

    async function withCleanup() {
      try {
        return await operation();
      } finally {
        cleanup();
      }
    }
  • Throwing errors

    Throw errors from async functions to propagate them as promise rejections.

  • Chained catch

    Attach .catch() to an async call when you prefer promise chaining instead.

    fetchData().then(data => process(data)).catch(error => console.error("Failed:", error.message));
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async and Await
Chapter 13 · Page 109
Intermediate

JavaScript Async and Await

(continued)

Parallel Execution

  • Promise.all()

    Runs every promise concurrently and resolves once all of them succeed.

    async function getUsers() {
      const [user1, user2] = await Promise.all([
        fetch("/users/1").then(r => r.json()),
        fetch("/users/2").then(r => r.json())
      ]);
      return [user1, user2];
    }
  • Faster than sequential

    Running promises together is much faster than awaiting each one in turn.

  • Promise.race()

    Resolves or rejects as soon as the first promise settles, whichever it is.

    const fastest = await Promise.race([api1(), api2()]);
  • Promise.allSettled()

    Waits for every promise to finish and reports each result, even failures.

  • Promise.any()

    Resolves as soon as the first promise succeeds, ignoring earlier rejections.

    const result = await Promise.any([
      fetch("/endpoint-1").then(r => r.json()),
      fetch("/endpoint-2").then(r => r.json())
    ]);
    // Resolves with whichever responds first without rejecting
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async and Await
Chapter 13 · Page 110
Intermediate

JavaScript Async and Await

(continued)

Common Patterns

  • Top-level await

    ES modules can await at the top level without a wrapping async function.

    // In a module
    const config = await loadConfig();
  • Chained workflow

    Chain multiple async operations together, each awaiting the previous result.

    async function workflow() {
      const data = await fetch1();
      const result = await process(data);
      return await fetch2(result);
    }
  • Async IIFE

    Use an async IIFE for immediate async execution without a named function.

    (async () => {
      const data = await fetchData();
      console.log(data);
    })();
  • for-await-of

    Loop over async iterables item by item using for-await-of.

    for await (const item of asyncIterator()) {
      console.log(item);
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async and Await
Chapter 13 · Page 111
Intermediate

JavaScript Async and Await

(FAQ)

FAQ

Declaring a function with async makes it automatically return a Promise, even if you return a plain value. This means callers can use .then() or await on it without any extra wrapping.

At the top level of ES modules, you can use top-level await directly. Inside regular scripts or non-async functions, wrap your code in an async function first. Attempting await in a non-async context throws a SyntaxError.

Wrap your awaited calls in a try/catch block. The catch block receives the rejection reason, just like a .catch() handler on a Promise chain. You can also attach .catch() directly to an awaited expression if you only need to handle one specific call.

They are functionally equivalent — async/await is syntactic sugar over Promises that makes asynchronous code read like synchronous code. Use async/await for cleaner control flow and easier debugging. Use Promise chains when composing reusable utility functions or when you prefer a functional style.

Store each async call in a variable without awaiting it immediately. Then pass the resulting Promises to Promise.all() and await that. This kicks off all operations concurrently, so total time equals the slowest operation rather than the sum of all.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async and Await
Chapter 13 · Page 112
Intermediate

JavaScript Async and Await

(In Practice)
In Practice

Loading a Dashboard with Parallel Requests

Combines Promise.all with async/await to fetch a user's profile and stats in parallel, with a fallback if either request fails.

  1. 01Promise.all() kicks off both fetch calls at the same time instead of one after another.
  2. 02await pauses until both promises resolve, then the responses are parsed as JSON.
  3. 03The try/catch block catches a failure in either request and returns a safe fallback.
  4. 04Total time equals the slowest request, not the sum of both requests.
async function loadDashboard(userId) {
  try {
    const [profileRes, statsRes] = await Promise.all([
      fetch(`/api/users/${userId}`),
      fetch(`/api/users/${userId}/stats`),
    ]);
    const profile = await profileRes.json();
    const stats = await statsRes.json();
    return { profile, stats };
  } catch (error) {
    console.error('Dashboard load failed:', error);
    return { profile: null, stats: null };
  }
}

loadDashboard(42).then(data => console.log(data));
Takeaway

Promise.all() plus try/catch runs independent requests in parallel while still handling failures in one place.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Classes
Chapter 14 · Page 113
Intermediate

JavaScript Classes

Build objects with class syntax covering constructors, inheritance, static members, and private fields.

TL;DR

  1. 01Define object blueprints with class and constructor syntax.
  2. 02Inherit shared behavior using extends and super() calls.
  3. 03Hide internal state with private fields marked by #.

Tips

  1. 01Use private fields with a hash prefix to stop outside code from reading or changing internal state directly.
  2. 02Call super() before using this in a subclass constructor, since the parent must initialize the instance first.
  3. 03Prefer static methods for utility functions that relate to a class but don't need a specific instance.

Warnings

  1. 01Forgetting to call super() in a subclass constructor throws a ReferenceError before this can be accessed.
  2. 02Arrow function class fields capture this permanently, which can surprise developers expecting normal method binding rules.
  3. 03Class declarations are not hoisted like functions, so using a class before its definition throws an error.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Classes
Chapter 14 · Page 114
Intermediate

JavaScript Classes

(continued)

Class Basics

  • class + constructor

    Define a blueprint for creating objects with shared methods.

    class User {
      constructor(name, email) {
        this.name = name;
        this.email = email;
      }
    }
  • new keyword

    Create instances with new, which runs the constructor automatically.

    const user = new User('Ana', 'ana@example.com');
    console.log(user.name); // "Ana"
  • Instance methods

    Define instance methods inside the class body without the function keyword.

    class User {
      constructor(name) {
        this.name = name;
      }
      greet() {
        return `Hi, ${this.name}`;
      }
    }
  • Shared prototype

    Methods live on the prototype, so every instance shares one copy instead of duplicating.

    const a = new User('Ana');
    const b = new User('Leo');
    console.log(a.greet === b.greet); // true
  • Strict mode

    Class declarations run in strict mode automatically, catching more silent bugs.

    class Demo {
      constructor() {
        undeclaredVar = 1; // throws ReferenceError in strict mode
      }
    }
  • No hoisting

    Classes are not hoisted the way function declarations are, so define them before use.

    // new Greeter() here would throw a ReferenceError
    class Greeter {}
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Classes
Chapter 14 · Page 115
Intermediate

JavaScript Classes

(continued)

Static Methods and Properties

  • static method

    Mark a method static to attach it to the class itself instead of each instance.

    class MathHelper {
      static square(n) {
        return n * n;
      }
    }
    MathHelper.square(4); // 16
  • No instance this

    Static methods cannot access instance data through this because no instance exists.

    class Counter {
      static count = 0;
      constructor() {
        Counter.count++;
      }
    }
  • Shared data

    Use static properties to track data shared across all instances, like a running total.

    new Counter();
    new Counter();
    console.log(Counter.count); // 2
  • Factory methods

    Build factory methods as static functions that return configured instances.

    class User {
      static fromJSON(json) {
        const data = JSON.parse(json);
        return new User(data.name, data.email);
      }
    }
  • Static blocks

    Static blocks let you run setup logic once when the class is first defined.

    class Config {
      static settings;
      static {
        Config.settings = loadDefaults();
      }
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Classes
Chapter 14 · Page 116
Intermediate

JavaScript Classes

(continued)

Getters, Setters, and Private Fields

  • get

    Define a property that computes its value each time it's read.

    class Circle {
      constructor(radius) {
        this.radius = radius;
      }
      get area() {
        return Math.PI * this.radius ** 2;
      }
    }
  • set

    Run logic, like validation, whenever a property is assigned.

    class Circle {
      set radius(value) {
        if (value <= 0) throw new RangeError('Radius must be positive');
        this._radius = value;
      }
    }
  • Private fields (#)

    Mark fields private with a leading # so they can't be read or changed outside the class.

    class BankAccount {
      #balance = 0;
      deposit(amount) {
        this.#balance += amount;
      }
      get balance() {
        return this.#balance;
      }
    }
  • Enforced privacy

    Accessing a private field from outside the class throws a SyntaxError, not just undefined.

    const acc = new BankAccount();
    acc.#balance; // SyntaxError: Private field must be declared in an enclosing class
  • Private methods

    Private methods work the same way, hiding internal logic from the public API.

    class Order {
      #calculateTax(amount) {
        return amount * 0.08;
      }
      getTotal(amount) {
        return amount + this.#calculateTax(amount);
      }
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Classes
Chapter 14 · Page 117
Intermediate

JavaScript Classes

(continued)

Inheritance with Extends and Super

  • extends

    Create a subclass that inherits methods and properties from a parent.

    class Animal {
      constructor(name) {
        this.name = name;
      }
      speak() {
        return `${this.name} makes a sound`;
      }
    }
    class Dog extends Animal {}
  • super()

    Call super() inside a subclass constructor to run the parent constructor first.

    class Dog extends Animal {
      constructor(name, breed) {
        super(name);
        this.breed = breed;
      }
    }
  • Overriding methods

    Override a parent method by redefining it with the same name in the subclass.

    class Dog extends Animal {
      speak() {
        return `${this.name} barks`;
      }
    }
  • super.method()

    Call super.methodName() to reuse parent logic instead of duplicating it.

    class Dog extends Animal {
      speak() {
        return `${super.speak()} loudly`;
      }
    }
  • instanceof

    Check whether an object inherits from a given class.

    const rex = new Dog('Rex', 'Lab');
    console.log(rex instanceof Animal); // true
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Classes
Chapter 14 · Page 118
Intermediate

JavaScript Classes

(continued)

Classes vs Prototypes

  • Syntactic sugar

    Classes are syntactic sugar over JavaScript's existing prototype-based inheritance model.

    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    }
    // Roughly equivalent to a constructor function + prototype assignment
  • Methods on prototype

    A class method becomes a non-enumerable property on the constructor's prototype object.

    class Point {
      distanceTo(other) {
        return Math.hypot(this.x - other.x, this.y - other.y);
      }
    }
    console.log(typeof Point.prototype.distanceTo); // "function"
  • typeof a class

    The typeof a class is still "function", confirming classes are functions under the hood.

    console.log(typeof Point); // "function"
  • Requires new

    Unlike old-style constructor functions, classes throw an error if called without new.

    function OldStyle() {}
    OldStyle(); // works (but usually a bug)
    
    class NewStyle {}
    NewStyle(); // TypeError: Class constructor cannot be invoked without 'new'
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Classes
Chapter 14 · Page 119
Intermediate

JavaScript Classes

(FAQ)

FAQ

A class field declares a property directly on the class body, and it runs before the constructor body executes. A constructor assignment sets the property inside the constructor function instead. Both end up creating the same instance property, but fields are often shorter for simple defaults.

Yes, classes compile down to the same prototype-based inheritance JavaScript always used. Methods defined in a class body are added to the prototype, not to each instance. Classes simply give that pattern cleaner, more familiar syntax.

An underscore prefix like _name is just a convention; outside code can still access it. A true private field written as #name is enforced by the engine. Accessing it from outside the class throws an error, so private fields offer real encapsulation, not just a hint.

Use a static method when the logic doesn't depend on a specific instance, like a factory function or a helper. Static methods are called on the class itself, such as MyClass.create(). Instance methods need this to refer to specific object data.

No, a class cannot have a field and an accessor pair with the same name; that throws a SyntaxError. Pick one approach: a plain field for simple storage, or a getter/setter pair for computed values. Use accessors when you need validation logic too.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Classes
Chapter 14 · Page 120
Intermediate

JavaScript Classes

(In Practice)
In Practice

Modeling a Savings Account with Inheritance

A SavingsAccount subclass extends a base Account class, using super(), a private field, and a getter to apply interest safely.

  1. 01Account keeps #balance private, exposing it only through a read-only balance getter.
  2. 02SavingsAccount extends Account and calls super() to initialize the shared owner and balance fields.
  3. 03applyInterest() reads this.balance through the inherited getter, then calls the inherited deposit() method.
  4. 04instanceof confirms SavingsAccount still inherits from Account despite adding its own behavior.
class Account {
  #balance;
  constructor(owner, balance = 0) {
    this.owner = owner;
    this.#balance = balance;
  }
  deposit(amount) {
    this.#balance += amount;
    return this.#balance;
  }
  get balance() {
    return this.#balance;
  }
}

class SavingsAccount extends Account {
  constructor(owner, balance, rate) {
    super(owner, balance);
    this.rate = rate;
  }
  applyInterest() {
    const interest = this.balance * this.rate;
    return this.deposit(interest);
  }
}

const savings = new SavingsAccount('Priya', 1000, 0.05);
savings.applyInterest();
console.log(savings.balance); // 1050
console.log(savings instanceof Account); // true
Takeaway

extends plus super() lets a subclass reuse private state and methods it can't access directly.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Error Handling
Chapter 15 · Page 121
Intermediate

JavaScript Error Handling

Handle errors gracefully in JavaScript using try/catch, custom error classes, and finally blocks.

TL;DR

  1. 01Wrap risky code in try/catch to handle thrown errors cleanly.
  2. 02Throw custom error classes to make catch blocks more precise.
  3. 03Use finally to run cleanup code regardless of success or failure.

Tips

  1. 01Create custom error classes to identify error types in catch blocks — makes branching logic far clearer than checking messages.
  2. 02Use finally blocks to release resources like file handles or database connections, since they run regardless of errors.
  3. 03Re-throw an error after logging it so calling code further up the stack still gets a chance to handle it.

Warnings

  1. 01Never swallow errors silently with an empty catch block — always log or handle them so bugs don't disappear.
  2. 02Throwing a plain string instead of an Error object loses the automatic stack trace, making bugs harder to track down.
  3. 03A return statement inside finally silently overrides any return or thrown error from the try or catch block above it.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Error Handling
Chapter 15 · Page 122
Intermediate

JavaScript Error Handling

(continued)

Try/Catch Basics

  • try/catch

    Wrap risky code in a try block to intercept runtime errors.

    try {
      const result = riskyOperation();
      console.log(result);
    } catch (error) {
      console.error('Error:', error.message);
    }
  • Catch only runs on error

    The catch block only runs when an error is thrown in try.

    try {
      const data = JSON.parse('invalid');
    } catch (error) {
      console.error('Caught:', error.message); // SyntaxError
    }
  • Error object properties

    The error object contains a message, name, and a stack trace.

    catch (error) {
      console.log(error.name);    // "SyntaxError"
      console.log(error.message); // "Unexpected token i"
      console.log(error.stack);   // full trace
    }
  • Execution stops at throw

    Code inside try after the thrown line does not execute.

    try {
      throw new Error('stop here');
      console.log('never runs');
    } catch (e) {
      console.log(e.message); // "stop here"
    }
  • Optional catch binding

    Omit the catch binding if you don't need the error object.

    try {
      mayFail();
    } catch {
      // optional binding — no variable needed
      console.log('Something went wrong');
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Error Handling
Chapter 15 · Page 123
Intermediate

JavaScript Error Handling

(continued)

Finally Block

  • Always runs

    Run cleanup code with finally, which always executes.

    try {
      const file = openFile('data.txt');
      processFile(file);
    } catch (error) {
      console.error('Error:', error);
    } finally {
      closeFile(); // Always runs
    }
  • Runs without an error

    Finally runs even when there is no error in try.

  • Runs before return

    Finally runs even if catch re-throws or the try block returns early.

    function getData() {
      try {
        return fetchData();
      } finally {
        cleanup(); // runs before function returns
      }
    }
  • Releasing resources

    Use finally to release resources like connections or file handles.

    let connection;
    try {
      connection = openDB();
      return connection.query('SELECT * FROM users');
    } finally {
      connection?.close();
    }
  • Resetting UI state

    Finally is useful for resetting loading or spinner state in UIs.

    setLoading(true);
    try {
      await fetchData();
    } finally {
      setLoading(false); // runs on success or failure
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Error Handling
Chapter 15 · Page 124
Intermediate

JavaScript Error Handling

(continued)

Throwing Errors

  • throw new Error()

    Throw a new Error with a descriptive message.

    function divide(a, b) {
      if (b === 0) {
        throw new Error('Division by zero');
      }
      return a / b;
    }
  • Error objects, not strings

    You can throw any value, but Error objects are best practice.

    // Avoid: throw 'something went wrong';
    // Prefer: throw new Error('something went wrong');
  • Built-in error types

    Throw built-in error types for more specific problems.

    function setAge(age) {
      if (typeof age !== 'number') {
        throw new TypeError('Age must be a number');
      }
      if (age < 0 || age > 150) {
        throw new RangeError('Age out of valid range');
      }
    }
  • Re-throwing

    Re-throw errors after logging to let upstream code handle them.

    try {
      riskyOp();
    } catch (e) {
      logger.error(e);
      throw e; // propagate to caller
    }
  • Throwing inside catch

    Throwing inside a catch block escalates the error upstream.

    catch (error) {
      if (error instanceof SyntaxError) {
        throw new Error('Config file is malformed');
      }
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Error Handling
Chapter 15 · Page 125
Intermediate

JavaScript Error Handling

(continued)

Custom Error Classes

  • Extending Error

    Create custom error types by extending the built-in Error class.

    class ValidationError extends Error {
      constructor(message) {
        super(message);
        this.name = 'ValidationError';
      }
    }
  • instanceof checks

    Check error type with instanceof in catch blocks.

    try {
      if (!email.includes('@')) {
        throw new ValidationError('Invalid email');
      }
    } catch (error) {
      if (error instanceof ValidationError) {
        console.log('Validation error:', error.message);
      }
    }
  • Extra properties

    Add extra properties to custom errors for richer context.

    class HttpError extends Error {
      constructor(status, message) {
        super(message);
        this.name = 'HttpError';
        this.status = status;
      }
    }
    throw new HttpError(404, 'Resource not found');
  • Multiple error classes

    Use multiple custom error classes to categorize problems.

    class NetworkError extends Error { }
    class AuthError extends Error { }
    class NotFoundError extends Error { }
  • Branching in catch

    Handle specific error types separately, letting unknown errors bubble up.

    catch (error) {
      if (error instanceof AuthError) return redirectToLogin();
      if (error instanceof NetworkError) return showRetry();
      throw error; // unknown errors bubble up
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Error Handling
Chapter 15 · Page 126
Intermediate

JavaScript Error Handling

(continued)

Common Error Types

  • SyntaxError

    Occurs when code or data cannot be parsed.

    try {
      JSON.parse('invalid json');
    } catch (error) {
      if (error instanceof SyntaxError) {
        console.log('Invalid JSON format');
      }
    }
  • TypeError

    Occurs when a value is used with the wrong type.

    try {
      const x = null;
      x.method(); // TypeError: Cannot read properties of null
    } catch (e) {
      console.log(e instanceof TypeError); // true
    }
  • ReferenceError

    Occurs when a variable is not defined.

    try {
      console.log(undeclaredVar);
    } catch (e) {
      console.log(e instanceof ReferenceError); // true
    }
  • RangeError

    Occurs when a number falls outside valid bounds.

    try {
      new Array(-1); // RangeError: Invalid array length
    } catch (e) {
      console.log(e instanceof RangeError); // true
    }
  • error.name

    Check error names as a string alternative to instanceof.

    catch (error) {
      console.log(error.name); // "TypeError", "RangeError", etc.
      if (error.name === 'TypeError') handleTypeError(error);
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Error Handling
Chapter 15 · Page 127
Intermediate

JavaScript Error Handling

(FAQ)

FAQ

Yes — wrap your await call inside a try/catch block and it will catch rejected promises just like synchronous errors. Alternatively, chain .catch() on the promise, but try/catch keeps async error handling visually consistent with synchronous code.

Yes, finally always executes before the function actually returns, even if try or catch contains a return. Be careful not to place a return inside finally itself. It overrides any return value from try or catch.

Always throw an Error object (or a subclass), never a plain string. Error objects capture a stack trace automatically, which is essential for debugging. Thrown strings produce no stack trace and are much harder to track down.

Use instanceof to branch on the error's class: if (err instanceof ValidationError) handles it differently from if (err instanceof NetworkError). This is why custom error classes are worth defining. Checking err.message with string matching is fragile and breaks as messages change.

A ReferenceError means you accessed a variable that doesn't exist in scope. A TypeError means a value exists but you're using it in an incompatible way, like calling null as a function. Recognizing which one you have narrows down the likely cause of the bug.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Error Handling
Chapter 15 · Page 128
Intermediate

JavaScript Error Handling

(In Practice)
In Practice

Validating and Fetching User Data Safely

Combines a custom ValidationError class, try/catch/finally, and instanceof checks to handle distinct failure modes cleanly.

  1. 01ValidationError extends Error so it carries a stack trace and can be caught with instanceof.
  2. 02Invalid input throws before the fetch even starts, keeping validation separate from network errors.
  3. 03The catch block branches on instanceof to give validation and network failures different handling.
  4. 04finally always resets the loading state, whether the request succeeded, failed, or never started.
class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = 'ValidationError';
  }
}

async function getUser(id) {
  if (typeof id !== 'number') {
    throw new ValidationError('id must be a number');
  }

  setLoading(true);
  try {
    const res = await fetch(`/api/users/${id}`);
    if (!res.ok) throw new Error(`Request failed: ${res.status}`);
    return await res.json();
  } catch (error) {
    if (error instanceof ValidationError) {
      console.error('Bad input:', error.message);
    } else {
      console.error('Fetch failed:', error.message);
    }
    return null;
  } finally {
    setLoading(false);
  }
}
Takeaway

Custom error classes plus instanceof checks let one catch block handle different failure types distinctly.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Events
Chapter 16 · Page 129
Intermediate

JavaScript Events

Handle browser events, event delegation, bubbling, capturing, and preventDefault with vanilla JavaScript.

TL;DR

  1. 01Attach event listeners with addEventListener for flexible handling.
  2. 02Use event delegation to handle many items with one listener.
  3. 03Control event flow with stopPropagation and preventDefault when needed.

Tips

  1. 01Use event delegation to attach a single listener to a container instead of many listeners on child elements.
  2. 02Pass the { once: true } option to addEventListener when a handler should only run a single time.
  3. 03Check event.cancelable before calling preventDefault, since some events like scroll cannot be canceled at all.

Warnings

  1. 01preventDefault only works on cancelable events — always check if the event is cancelable before calling it.
  2. 02Inline handlers like onclick can only hold one function, so a second assignment silently replaces the first one.
  3. 03Forgetting removeEventListener on elements you remove from the DOM can leak memory in long-running single-page applications.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Events
Chapter 16 · Page 130
Intermediate

JavaScript Events

(continued)

Basic Event Listeners

  • addEventListener()

    Attach event handlers for flexible, composable event handling.

    const button = document.querySelector("button");
    button.addEventListener("click", (event) => {
      console.log("Button clicked");
    });
  • The event object

    Contains details about what happened, like type, target, and position.

    button.addEventListener("click", (e) => {
      console.log(e.type);      // "click"
      console.log(e.target);    // the button element
      console.log(e.clientX);   // mouse position
    });
  • removeEventListener()

    Removes a listener when it's no longer needed.

    const handler = (e) => console.log("clicked");
    button.addEventListener("click", handler);
    button.removeEventListener("click", handler);
  • Avoid inline handlers

    Inline event handlers like onclick are outdated compared to addEventListener.

    // Avoid: <button onclick="handleClick()">Click</button>
    // Use addEventListener instead
  • { once: true }

    Fires a listener only one time, then removes it automatically.

    button.addEventListener("click", handler, { once: true });
    // Handler is automatically removed after first click
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Events
Chapter 16 · Page 131
Intermediate

JavaScript Events

(continued)

Event Bubbling and Capturing

  • Bubbling by default

    Events bubble up from child to parent by default.

    div.addEventListener("click", () => console.log("div clicked"));
    button.addEventListener("click", () => console.log("button clicked"));
    // Clicking button logs both "button clicked" and "div clicked"
  • stopPropagation()

    Prevents an event from bubbling up to parent listeners.

    button.addEventListener("click", (e) => {
      e.stopPropagation();
      console.log("button only");
    });
  • Capture phase

    Pass true as the third argument to listen during the capture phase.

    div.addEventListener("click", handler, true);
    // Capture phase runs before bubble phase
  • Most events bubble

    Most events bubble, but check the MDN docs for specific events that don't.

  • Blocking parent handlers

    Use stopPropagation to prevent parent handlers from running at all.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Events
Chapter 16 · Page 132
Intermediate

JavaScript Events

(continued)

Preventing Default Behavior

  • preventDefault()

    Stops the browser's default action for an event.

    form.addEventListener("submit", (e) => {
      e.preventDefault();
      // Form does not submit to server
      console.log("Form submission intercepted");
    });
  • Common use cases

    Works on clickable links, form submissions, and other cancelable events.

    link.addEventListener("click", (e) => {
      e.preventDefault();
      // Link does not navigate to href
    });
  • event.defaultPrevented

    Check whether preventDefault was already called on the event.

    if (!event.defaultPrevented) {
      // Default action will occur
    }
  • Not all events cancelable

    Not all events can be prevented — check if the event is cancelable first.

  • event.cancelable

    Verify the event supports preventDefault before calling it.

    link.addEventListener("click", (e) => {
      if (e.cancelable) {
        e.preventDefault();
      }
    });
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Events
Chapter 16 · Page 133
Intermediate

JavaScript Events

(continued)

Event Delegation

  • One listener, many children

    Attach a single listener to a parent to handle children efficiently.

    const list = document.querySelector("ul");
    list.addEventListener("click", (e) => {
      if (e.target.tagName === "LI") {
        console.log("Clicked item:", e.target.textContent);
      }
    });
  • Fewer listeners

    This pattern is efficient when there are many similar elements.

    // Instead of attaching listeners to each item:
    items.forEach(item => item.addEventListener("click", handler));
    
    // Attach one listener to the container:
    container.addEventListener("click", handler);
  • e.target.closest()

    Finds the closest matching ancestor from the actual clicked element.

    document.addEventListener("click", (e) => {
      const button = e.target.closest("button");
      if (button) console.log("Button clicked");
    });
  • Works with dynamic elements

    Delegation works with elements added to the DOM after the listener was attached.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Events
Chapter 16 · Page 134
Intermediate

JavaScript Events

(continued)

Common Events

  • Mouse events

    click, dblclick, mousedown, mouseup, and mousemove track pointer activity.

    element.addEventListener("mousemove", (e) => {
      console.log(`Mouse at ${e.clientX}, ${e.clientY}`);
    });
  • Keyboard events

    keydown and keyup track key presses; keypress is deprecated.

    document.addEventListener("keydown", (e) => {
      console.log(`Key pressed: ${e.key}`);
    });
  • Form events

    change, input, submit, reset, focus, and blur track form interaction.

    input.addEventListener("input", (e) => {
      console.log(`Current value: ${e.target.value}`);
    });
  • Window events

    load, unload, scroll, and resize track the page and viewport.

    window.addEventListener("scroll", () => {
      console.log("Page scrolled");
    });
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Events
Chapter 16 · Page 135
Intermediate

JavaScript Events

(FAQ)

FAQ

Bubbling propagates events from the target element up to the root; capturing goes from root down to the target. Pass true as the third argument to addEventListener to use capturing phase instead of the default bubbling.

Call event.stopPropagation() inside your handler to prevent the event from bubbling up. Use event.stopImmediatePropagation() if you also want to block other listeners on the same element.

Attach one listener to a parent element and use event.target to identify which child triggered the event. This is especially useful for dynamically added elements or large lists. Listeners on the parent automatically cover new children.

Not all events are cancelable — for example, scroll events cannot be prevented after they fire. Check event.cancelable before calling preventDefault(), and for scroll/touch performance consider using a passive event listener ({passive: true}).

onclick can only hold one handler at a time and overwrites any previously assigned function. addEventListener supports multiple handlers on the same element. It also gives you control over phase (capture vs bubble) and one-time execution via {once: true}.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Events
Chapter 16 · Page 136
Intermediate

JavaScript Events

(In Practice)
In Practice

Validating a Form with Delegated Listeners

One delegated submit listener validates required fields and prevents submission until every field passes.

  1. 01The submit listener checks every required field before the browser submits the form.
  2. 02e.preventDefault() only runs when validation fails, so a valid form submits normally.
  3. 03A single delegated input listener clears the error class as the user types, without per-field listeners.
  4. 04closest('[required]') confirms the input that fired the event is actually one that needs validation.
const form = document.querySelector('#signup-form');

form.addEventListener('submit', (e) => {
  const invalid = [...form.querySelectorAll('[required]')].filter(field => !field.value.trim());

  if (invalid.length > 0) {
    e.preventDefault();
    invalid.forEach(field => field.classList.add('error'));
    console.log(`${invalid.length} field(s) missing`);
  }
});

form.addEventListener('input', (e) => {
  const field = e.target.closest('[required]');
  if (field) field.classList.remove('error');
});
Takeaway

Two delegated listeners — submit and input — validate an entire form without attaching a listener to each field.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Fetch API
Chapter 17 · Page 137
Intermediate

JavaScript Fetch API

Master the Fetch API for making HTTP requests in JavaScript, including GET, POST, error handling, and working with JSON responses.

TL;DR

  1. 01Use fetch() to make HTTP requests and await the response.
  2. 02Check response.ok, since fetch rejects only on network failure.
  3. 03Use async/await with try/catch for clean, readable fetch code.

Tips

  1. 01In Next.js App Router, prefer the built-in extended fetch, since it supports cache and revalidate options for data fetching.
  2. 02Always wrap fetch calls in try/catch and check response.ok, so both network failures and HTTP error responses get handled consistently.
  3. 03Use an AbortController to cancel in-flight requests on unmount, which prevents wasted network calls and stale state updates.

Warnings

  1. 01Calling response.json() on an error response that returns HTML, like a 404 page, throws a JSON parse error.
  2. 02Use res.text() as a safe fallback when the content type of a response is unknown or unconfirmed.
  3. 03Forgetting to set the Content-Type header on a POST request can cause the server to misparse the JSON body.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Fetch API
Chapter 17 · Page 138
Intermediate

JavaScript Fetch API

(continued)

Basic GET Request

  • fetch()

    Returns a Promise that resolves to a Response object, the entry point for every request.

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

    True for status codes 200-299 — always check it before trusting the response.

  • response.json()

    Parses the response body as JSON and returns another Promise.

    const data = await response.json();
  • Network-only rejection

    fetch only rejects on network-level failures; a 404 or 500 still resolves successfully.

  • Replaces XMLHttpRequest

    Fetch is the modern, promise-based replacement for the older XMLHttpRequest API.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Fetch API
Chapter 17 · Page 139
Intermediate

JavaScript Fetch API

(continued)

POST Request with JSON Body

  • Sending JSON

    Set method, headers, and body in the options object to send data.

    async function createPost(data) {
      const response = await fetch('/api/posts', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });
      if (!response.ok) throw new Error('Request failed');
      return response.json();
    }
  • method

    Sets the HTTP verb, like 'POST', 'PUT', or 'DELETE'.

  • headers

    Sets request headers, most commonly Content-Type for JSON bodies.

    headers: { 'Content-Type': 'application/json' }
  • body

    Holds the request payload, usually JSON.stringify(data) for JSON APIs.

    body: JSON.stringify(data)
  • credentials

    Controls whether cookies are sent, e.g. 'include' or 'same-origin'.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Fetch API
Chapter 17 · Page 140
Intermediate

JavaScript Fetch API

(continued)

Error Handling Patterns

  • Robust try/catch

    Handle both network errors and HTTP error responses in one function.

    async function safeFetch(url, options = {}) {
      try {
        const res = await fetch(url, options);
        if (!res.ok) {
          const msg = await res.text();
          throw new Error(`${res.status}: ${msg}`);
        }
        return await res.json();
      } catch (err) {
        console.error('Fetch failed:', err);
        throw err;
      }
    }
  • Network-level errors

    Wrap fetch in try/catch to catch network-level errors like being offline or CORS failures.

  • HTTP error status

    Check response.ok inside the try block to catch HTTP errors (4xx, 5xx).

  • Reading the error body

    Read res.text() or res.json() on error responses to get the server's error message.

    const msg = await res.text();
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Fetch API
Chapter 17 · Page 141
Intermediate

JavaScript Fetch API

(continued)

Common Fetch Patterns

  • Auth token

    Send a bearer token in the Authorization header.

    headers: { Authorization: 'Bearer ' + token }
  • Form data

    Send a FormData body directly — no Content-Type header needed.

    body: new FormData(formEl)
  • Abort a request

    Cancel an in-flight request with AbortController.

    const ac = new AbortController();
    fetch(url, { signal: ac.signal });
  • Read plain text

    Read a non-JSON response body as text.

    const text = await response.text();
  • Download a blob

    Read a binary response body as a Blob.

    const blob = await response.blob();
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Fetch API
Chapter 17 · Page 142
Intermediate

JavaScript Fetch API

(continued)

Fetch vs Alternatives

  • fetch()

    Best for simple requests with no extra dependencies; error handling is more verbose and there are no interceptors.

  • axios

    Best for complex apps needing interceptors and retries; adds an external dependency of about 15 kB gzipped.

  • SWR / React Query

    Best for data fetching in React with built-in caching; framework-specific and needs more setup.

  • tRPC

    Best for full-stack TypeScript with end-to-end types; requires a matching server setup.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Fetch API
Chapter 17 · Page 143
Intermediate

JavaScript Fetch API

(FAQ)

FAQ

fetch() only rejects its promise on network-level failures (e.g., no internet, DNS error). HTTP error status codes like 404 or 500 resolve successfully. You must check response.ok or response.status manually before treating the response as valid.

Set the method to 'POST', add a 'Content-Type': 'application/json' header, and pass JSON.stringify(yourData) as the body. Without the Content-Type header, many servers won't parse the payload correctly.

fetch() is built into modern browsers and Node.js 18+, making it a solid zero-dependency choice for most projects. Axios adds value if you need request/response interceptors, automatic JSON serialization, or broader legacy browser support out of the box.

Wrap your fetch call in a try/catch to handle network failures. Inside the try block, explicitly check response.ok and throw a new Error for HTTP errors. This lets your catch block handle both failure types in one place.

Yes — Next.js App Router extends the native fetch with cache and next.revalidate options. This lets you control caching and incremental static regeneration directly in server components without any additional library.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Fetch API
Chapter 17 · Page 144
Intermediate

JavaScript Fetch API

(In Practice)
In Practice

Fetching with Timeout and Graceful Cancellation

Combines AbortController, try/catch, and a response.ok check to fetch data that gives up after a timeout instead of hanging forever.

  1. 01The AbortController's signal is passed to fetch, giving the request a way to be cancelled mid-flight.
  2. 02setTimeout calls controller.abort() if the response doesn't arrive within timeoutMs.
  3. 03response.ok is checked separately from the try/catch, since fetch only rejects on network failures, not HTTP error codes.
  4. 04clearTimeout in finally cancels the pending timer once the request settles, whether it succeeded, failed, or timed out.
async function fetchWithTimeout(url, timeoutMs = 5000) {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);

  try {
    const response = await fetch(url, { signal: controller.signal });
    if (!response.ok) {
      throw new Error(`HTTP error: ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    if (error.name === 'AbortError') {
      throw new Error('Request timed out');
    }
    throw error;
  } finally {
    clearTimeout(timer);
  }
}

fetchWithTimeout('/api/users').then(data => console.log(data));
Takeaway

AbortController turns a fetch call into a cancellable operation — pair it with a timer to avoid requests that hang forever.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Modules
Chapter 18 · Page 145
Intermediate

JavaScript Modules

Organize JavaScript code with ES6 modules using named exports, default exports, and dynamic imports.

TL;DR

  1. 01Export functions and variables using named or default export syntax.
  2. 02Import named exports using curly braces and defaults without them.
  3. 03Use dynamic import() to load modules asynchronously at runtime.

Tips

  1. 01Use named exports for multiple utilities and reserve default exports for the primary object a module provides.
  2. 02Create barrel files named index.js to simplify deeply nested import statements across your application subfolders.

Warnings

  1. 01Avoid circular module dependencies where two files import each other, as this can generate unexpected undefined bindings.
  2. 02Attempting to declare more than one default export in a single module throws a compile-time SyntaxError.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Modules
Chapter 18 · Page 146
Intermediate

JavaScript Modules

(continued)

Named Exports

  • export

    Exposes functions, variables, or classes from a module under specific names.

    // math.js
    export function add(a, b) { return a + b; }
    export const PI = 3.14159;
  • import { ... }

    Imports specific named exports from another module file using curly brace syntax.

    import { add, PI } from "./math.js";
    console.log(add(5, PI));
  • import * as namespace

    Binds all named exports to a single namespace object variable.

    import * as Math from "./math.js";
    console.log(Math.add(5, 3));
    console.log(Math.PI);
  • Barrel re-export

    Re-exports items from other modules directly without importing them locally first.

    // index.js - barrel file
    export { add, subtract } from "./math.js";
    export { formatDate } from "./date.js";
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Modules
Chapter 18 · Page 147
Intermediate

JavaScript Modules

(continued)

Default Exports

  • export default

    Exposes a single primary export value, function, or class from a module.

    // logger.js
    export default function log(msg) {
      console.log(`[LOG] ${msg}`);
    }
  • Default import

    Imports a default export without using curly braces, using any local name.

    import log from "./logger.js";
    log("App started");
  • Class export

    Exports an entire ES6 class definition as the default export of a module.

    // UserService.js
    export default class UserService {
      getUser(id) { return { id }; }
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Modules
Chapter 18 · Page 148
Intermediate

JavaScript Modules

(continued)

Mixing and Re-exporting

  • Mixed imports

    Imports both default and named exports within a single import statement.

    import main, { helper, VERSION } from "./utils.js";
    main();
  • Default re-export

    Re-exports a default export as a named export inside barrel files.

    export { default as User } from "./User.js";
  • Renamed re-export

    Renames exports during the re-export process for public API clarity.

    export { add as sum } from "./math.js";
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Modules
Chapter 18 · Page 149
Intermediate

JavaScript Modules

(continued)

Renaming Imports

  • import as

    Renames imported values to prevent naming collisions with other local variables.

    import { add as addition } from "./math.js";
    addition(5, 3);
  • Conflict resolution

    Allows importing functions with identical names by mapping them to local aliases.

    import { format as formatDate } from "./date.js";
    import { format as formatMoney } from "./currency.js";
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Modules
Chapter 18 · Page 150
Intermediate

JavaScript Modules

(continued)

Module Side Effects

  • Side-effect import

    Imports a module purely for its side effects without binding any local variables.

    import "./polyfills.js";
    import "./analytics.js";
  • Cached evaluation

    Evaluates modules only once per application lifecycle, caching subsequent imports.

    import "./init.js"; // executes
    import "./init.js"; // loads from cache
  • dynamic import()

    Loads modules dynamically and asynchronously at runtime using promise logic.

    async function loadChart() {
      const { Chart } = await import("./chart.js");
      return new Chart();
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Modules
Chapter 18 · Page 151
Intermediate

JavaScript Modules

(FAQ)

FAQ

Use a default export for the primary component or class that a module provides. Choose named exports for utility functions or constants. This keeps imports consistent and easy to read.

Combine both exports into a single statement: import MyClass, { helperFn, CONST } from './module.js'. Place the default export before the curly braces containing the named exports.

Use the as keyword: import { render as renderList } from './list.js'. To rename default imports, simply choose a fresh local variable identifier during the import declaration.

Dynamic import() loads modules on demand at runtime and returns a Promise resolving to the module. Use it for lazy loading, route code splitting, or loading conditional scripts.

Circular dependencies cause modules to evaluate before their dependencies finish exporting. This leaves unfinished variables as undefined. Resolve this cycle by extracting shared variables to a third module.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Modules
Chapter 18 · Page 152
Intermediate

JavaScript Modules

(In Practice)
In Practice

Dynamic Theme Module Loading

Loads visual style themes dynamically at runtime using asynchronous imports to minimize the initial application bundle size.

  1. 01Construct the dynamic path to the theme file based on user selection.
  2. 02Invoke the dynamic import() function to request the module asynchronously.
  3. 03Access the default theme export from the resolved module namespace.
  4. 04Call the apply method on the theme object to update user styles.
  5. 05Catch and report loading errors if the selected theme is not found.
export async function loadTheme(name) {
  try {
    const path = `./themes/${name}.js`;
    const module = await import(path);
    const theme = module.default;
    theme.apply();
  } catch (err) {
    console.error(`Load failed: ${name}`, err);
  }
}
Takeaway

Utilize dynamic import() to lazy-load modules conditionally, reducing initial bundle sizes and improving page performance.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Optional Chaining
Chapter 19 · Page 153
Intermediate

JavaScript Optional Chaining

Access nested properties safely with optional chaining and pair it with nullish coalescing for defaults.

TL;DR

  1. 01Access nested properties safely using the ?. operator.
  2. 02Provide fallback values for missing properties using the ?? operator.
  3. 03Short-circuit evaluation chains immediately when any intermediate value is nullish.

Tips

  1. 01Combine the ?. and ?? operators to read nested properties and supply fallback values in one statement.
  2. 02Utilize optional chaining with ?.() when invoking callback methods that might not exist on target objects.

Warnings

  1. 01Remember that optional chaining only guards against null and undefined rather than other falsy values.
  2. 02Avoid overusing the ?. operator because it can hide actual bugs by silently swallowing unexpected errors.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Optional Chaining
Chapter 19 · Page 154
Intermediate

JavaScript Optional Chaining

(continued)

Optional Chaining Basics

  • ?.

    Accesses nested properties safely without throwing errors if the parent object is nullish.

    const user = { profile: null };
    const email = user.profile?.email; // undefined
  • Plain dot access

    Throws a TypeError if you attempt to read properties of a missing parent.

    const user = { profile: null };
    // Throws: Cannot read properties of null
    const email = user.profile.email;
  • Multi-level chaining

    Chains multiple optional checks together to guard against several missing layers.

    const data = {};
    const city = data.user?.address?.city; // undefined
  • Mixed chaining

    Combines optional chaining with standard dot access once existence is verified.

    const user = {
      profile: { settings: { theme: "dark" } }
    };
    const theme = user.profile?.settings.theme; // safe
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Optional Chaining
Chapter 19 · Page 155
Intermediate

JavaScript Optional Chaining

(continued)

Method and Array Access

  • ?.()

    Invokes an object method conditionally only if it is defined and executable.

    const obj = {};
    obj.greet?.(); // does nothing, no error
  • Optional callbacks

    Invokes optional callback parameters in a function safely to prevent errors.

    function handleClick(onClick) {
      onClick?.(); // calls only if provided
    }
  • ?.[index]

    Accesses array elements or computed keys safely when the parent list is nullish.

    const arr = null;
    const item = arr?.[0]; // undefined
  • Dynamic objects

    Combines optional brackets and dot identifiers when walking variable data shapes.

    const res = data?.items?.[0]?.name;
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Optional Chaining
Chapter 19 · Page 156
Intermediate

JavaScript Optional Chaining

(continued)

Nullish Coalescing

  • ??

    Returns the right-hand value only when the left-hand expression is nullish.

    const name = user.name ?? "Anonymous";
  • ?? versus ||

    Preserves falsy values like zero or empty strings, unlike standard logical OR.

    const count = 0;
    console.log(count ?? 10); // 0
    console.log(count || 10); // 10
  • Safeguard chain

    Combines optional chaining and nullish fallback to supply safe defaults.

    const theme = user.settings?.theme ?? "light";
  • ??=

    Assigns a default value to a variable only if it is currently nullish.

    let config = {};
    config.timeout ??= 3000;
    console.log(config.timeout); // 3000
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Optional Chaining
Chapter 19 · Page 157
Intermediate

JavaScript Optional Chaining

(continued)

Short-Circuiting

  • Evaluation halt

    Stops expression evaluation immediately when a nullish value is encountered.

    let called = false;
    const getEmail = () => { called = true; };
    const user = null;
    user?.getEmail();
    console.log(called); // false
  • Expressions value

    Resolves the entire chained expression to undefined when short-circuited.

    const val = null?.a?.b;
    console.log(val); // undefined
  • Independent checks

    Short-circuits exclusively at optional chain points rather than plain dots.

    const obj = { a: null };
    // Throws TypeError: Cannot read property c of null
    const val = obj.a?.b.c;
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Optional Chaining
Chapter 19 · Page 158
Intermediate

JavaScript Optional Chaining

(FAQ)

FAQ

Optional chaining verifies if the value to its left is null or undefined before accessing properties. If it is nullish, the expression short-circuits and evaluates to undefined. This prevents throwing TypeError errors.

The || operator falls back for any falsy value, including 0, empty strings, and false. The ?? operator only falls back for null or undefined. Use ?? when other falsy values are valid.

Yes, use ?.() to call a function only if it exists. Use ?.[index] to safely query array indexes or dynamic keys. Both forms resolve to undefined if the preceding value is nullish.

Yes, this behavior is known as short-circuiting. As soon as any link in the chain finds a nullish value, execution stops. The expression immediately returns undefined without executing subsequent operations.

No, you cannot use optional chaining on the left side of assignments. For example, obj?.prop = value throws a SyntaxError. The operator is strictly read-only and cannot write data.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Optional Chaining
Chapter 19 · Page 159
Intermediate

JavaScript Optional Chaining

(In Practice)
In Practice

Safely Loading Configuration Settings

Extracts nested settings from an optional server configuration object, applying defaults and executing callback functions safely.

  1. 01Isolate the network configuration block using optional property chaining.
  2. 02Resolve the server host name and port value, applying default fallbacks.
  3. 03Retrieve the application debug flag using nullish coalescing to preserve false values.
  4. 04Capture the initialization callback function using optional method verification.
  5. 05Assemble the final config object, invoking the callback conditionally.
function getAppConfig(serverConfig) {
  const net = serverConfig?.network;
  const host = net?.host ?? "localhost";
  const port = net?.port ?? 8080;
  const debug = serverConfig?.debug ?? false;
  const onReady = serverConfig?.callbacks?.onReady;

  return {
    connection: `${host}:${port}`,
    debug,
    initialize: () => onReady?.()
  };
}
Takeaway

Combine optional chaining and nullish coalescing to safely inspect dynamic objects and establish resilient default fallbacks.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Promises
Chapter 20 · Page 160
Intermediate

JavaScript Promises

Master asynchronous operations with promises, chaining methods, async/await syntax, and parallel combinators.

TL;DR

  1. 01Use Promise instances to manage deferred asynchronous values.
  2. 02Chain then(), catch(), and finally() handlers to process values.
  3. 03Leverage async and await for synchronous-looking promise code.

Tips

  1. 01Run independent asynchronous processes concurrently using Promise.all() to prevent blocking call pipelines.
  2. 02Utilize Promise.allSettled() when you need results from all operations, including individual rejections.

Warnings

  1. 01Forgetting to return a value inside a then() block breaks the promise chaining sequence.
  2. 02A single rejected promise in Promise.all() rejects the entire collection immediately without waiting.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Promises
Chapter 20 · Page 161
Intermediate

JavaScript Promises

(continued)

Creating Promises

  • new Promise()

    Constructs a promise wrapper by passing resolve and reject callback handles.

    const p = new Promise((resolve, reject) => {
      if (success) resolve(data);
      else reject(new Error("Failed"));
    });
  • Promise.resolve()

    Returns an already-fulfilled promise containing the supplied argument.

    Promise.resolve(42)
      .then(val => console.log(val));
  • Promise.reject()

    Returns an already-rejected promise containing the supplied error reason.

    Promise.reject(new Error("Failed"))
      .catch(err => console.error(err));
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Promises
Chapter 20 · Page 162
Intermediate

JavaScript Promises

(continued)

Handling Results

  • .then()

    Attaches a fulfillment handler to react when a promise resolves.

    promise.then(result => {
      console.log("Resolved:", result);
    });
  • .catch()

    Attaches a rejection handler to catch errors thrown in chains.

    promise.catch(error => {
      console.error("Caught error:", error);
    });
  • .finally()

    Attaches a callback that executes regardless of success or failure outcomes.

    promise.finally(() => {
      console.log("Operation completed");
    });
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Promises
Chapter 20 · Page 163
Intermediate

JavaScript Promises

(continued)

Promise Chaining

  • Chaining .then()

    Passes the return value of each handler to the next link.

    fetch("/api/users/1")
      .then(res => res.json())
      .then(user => console.log(user.name))
      .catch(err => console.error(err));
  • Sequential waiting

    Returns a new promise inside then to pause subsequent step execution.

    getUser(id)
      .then(user => getOrders(user.id))
      .then(orders => console.log(orders));
  • Error recovery

    Attaches a catch block to supply fallback values and continue chaining.

    fetch("/api/data")
      .catch(() => getCachedData())
      .then(data => render(data));
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Promises
Chapter 20 · Page 164
Intermediate

JavaScript Promises

(continued)

Combining Promises

  • Promise.all()

    Waits for all promises to resolve, rejecting instantly if any fail.

    const [a, b] = await Promise.all([p1, p2]);
  • Promise.race()

    Returns the result of the first promise to settle, resolving or rejecting.

    const fastest = await Promise.race([p1, p2]);
  • Promise.any()

    Returns the first successfully resolved promise, ignoring rejections.

    const firstOk = await Promise.any([p1, p2]);
  • Promise.allSettled()

    Waits for all promises to settle and returns their status array.

    const results = await Promise.allSettled([p1, p2]);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Promises
Chapter 20 · Page 165
Intermediate

JavaScript Promises

(continued)

Common Patterns

  • Parallel execution

    Initiates independent promises simultaneously to speed up total execution times.

    const p1 = fetchUser();
    const p2 = fetchPosts();
    const [user, posts] = await Promise.all([p1, p2]);
  • Promisifying callbacks

    Wraps a legacy callback function like setTimeout in a promise.

    const delay = ms => {
      return new Promise(r => setTimeout(r, ms));
    };
    await delay(1000);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Promises
Chapter 20 · Page 166
Intermediate

JavaScript Promises

(FAQ)

FAQ

Instantiate a new Promise((resolve, reject) => { ... }) wrapper. Call the resolve callback upon success. Invoke the reject callback with an error object if the operation fails.

Each await statement blocks execution until that specific promise settles. Sequentially awaiting independent operations increases execution times. Wrap them in Promise.all() to trigger parallel execution.

Unhandled rejections can crash Node.js processes or trigger console warnings in browsers. Always attach a .catch() block. Alternatively, wrap your asynchronous expressions in try-catch structures.

Promise.race() resolves or rejects as soon as the first input promise settles. Promise.any() waits for the first successful resolution, ignoring intermediate rejections. It throws an AggregateError if all fail.

No, a forEach loop is not designed to await asynchronous callbacks. The loop completes before the async callbacks finish executing. Use a standard for...of loop to ensure sequential execution.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Promises
Chapter 20 · Page 167
Intermediate

JavaScript Promises

(In Practice)
In Practice

Parallel Dashboard Resource Fetching

Loads user profiles and order histories concurrently using parallel fetch requests to minimize user interface load delay.

  1. 01Initiate the user fetch request without awaiting its resolution.
  2. 02Kick off the order fetch request simultaneously in the background.
  3. 03Combine both promises using Promise.all to await their concurrent completion.
  4. 04Parse the JSON content of both resolved responses in parallel.
  5. 05Catch any network or parsing error using a try-catch wrapper.
async function getDashboardData(userId) { 
  try {
    const userPromise = fetch(`/users/${userId}`);
    const ordersPromise = fetch(`/orders/${userId}`);

    const [userRes, ordersRes] = await Promise.all([
      userPromise,
      ordersPromise
    ]);

    return {
      user: await userRes.json(),
      orders: await ordersRes.json()
    };
  } catch (err) {
    console.error("Dashboard failed to load", err);
    return null;
  }
}
Takeaway

Use Promise.all() to trigger independent requests concurrently, significantly reducing response wait times.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Set and Map
Chapter 21 · Page 168
Intermediate

JavaScript Set and Map

Master collection structures using Set and Map, understand key differences, and implement dynamic data lookups.

TL;DR

  1. 01Use Set to store unique value collections and eliminate duplicates.
  2. 02Use Map to match key-value pairs using any key type.
  3. 03Query size and iterate directly using standard for-of loops.

Tips

  1. 01Deduplicate an array instantly by wrapping it in a Set and spreading it back.
  2. 02Initialize a new Map directly from objects using the static Object.entries() conversion method.

Warnings

  1. 01Remember that object keys in Map collections are compared using strict reference identity matches.
  2. 02Standard JSON.stringify() serialization does not natively support Set or Map collections.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Set and Map
Chapter 21 · Page 169
Intermediate

JavaScript Set and Map

(continued)

Set Basics

  • Set initialization

    Creates a new Set from an iterable, automatically filtering out duplicate values.

    const numbers = new Set([1, 2, 2, 3]);
    console.log(numbers); // Set { 1, 2, 3 }
  • add()

    Adds a new unique value to the Set collection and returns the Set.

    const colors = new Set();
    colors.add("red").add("blue");
  • has()

    Checks if a specific value exists in the Set using constant time lookup.

    const exists = colors.has("red"); // true
  • delete() and `clear()`

    Removes individual items or deletes all elements from the Set collection.

    colors.delete("red");
    colors.clear();
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Set and Map
Chapter 21 · Page 170
Intermediate

JavaScript Set and Map

(continued)

Map Basics

  • Map initialization

    Creates a Map storing key-value pairs, maintaining insertion order of keys.

    const config = new Map([
      ["timeout", 5000],
      ["retries", 3]
    ]);
  • set()

    Inserts or updates a value for a specific key in the Map.

    const user = new Map();
    user.set("name", "Alice");
  • get()

    Retrieves the value associated with a specific key, returning undefined if missing.

    const timeout = config.get("timeout"); // 5000
  • has() check

    Verifies if a key is present in the Map collection without reading it.

    const hasKey = config.has("timeout"); // true
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Set and Map
Chapter 21 · Page 171
Intermediate

JavaScript Set and Map

(continued)

Set vs Object

  • Type constraints

    Set preserves variable types, while object keys are coerced to strings.

    const set = new Set([1, "1"]); // Set { 1, "1" }
    const obj = {};
    obj[1] = "num";
    obj["1"] = "str"; // overrides obj[1]
  • Unique storage

    Set filters duplicates natively, while objects require manual checks to prevent overwrite.

    const set = new Set([5, 5, 5]);
    console.log(set.size); // 1
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Set and Map
Chapter 21 · Page 172
Intermediate

JavaScript Set and Map

(continued)

Map vs Object

  • Key types

    Map allows objects and functions as keys, whereas objects coerce keys to strings.

    const map = new Map();
    const keyObj = { id: 1 };
    map.set(keyObj, "metadata");
    console.log(map.get(keyObj)); // "metadata"
  • Size properties

    Map counts elements directly via size, whereas objects require key array length.

    const map = new Map([["a", 1]]);
    console.log(map.size); // 1
    const obj = { a: 1 };
    console.log(Object.keys(obj).length); // 1
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Set and Map
Chapter 21 · Page 173
Intermediate

JavaScript Set and Map

(continued)

Iteration and Conversion

  • Set iteration

    Loops through Set values directly using a standard for-of loop.

    const numbers = new Set([1, 2, 3]);
    for (const num of numbers) {
      console.log(num);
    }
  • Map iteration

    Destructures entries into key-value pairs during iteration loops.

    const user = new Map([["name", "Alice"]]);
    for (const [k, v] of user) {
      console.log(k, v);
    }
  • Spread conversions

    Converts collection elements back into standard arrays using the spread operator.

    const set = new Set([1, 2]);
    const arr = [...set]; // [1, 2]
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Set and Map
Chapter 21 · Page 174
Intermediate

JavaScript Set and Map

(FAQ)

FAQ

Use the has() method, which performs instant lookup check queries. This method is much faster than checking arrays with includes(). Set checks take constant time regardless of size.

Yes, you can use any value including objects and arrays as keys in a Map. These keys are matched by reference. Two separate empty objects are treated as two distinct keys.

Use the array spread operator within the Set constructor. For example, write new Set([...setA, ...setB]). This automatically merges all elements while discarding duplicate entries.

Choose Map when keys are not strings or when insertion order must be preserved. A Map is also optimized for frequent additions and removals. Plain objects work better for simple static configs.

Convert entries by spreading the collection: [...myMap]. This returns an array of key-value pairs. To get only keys or values, use [...myMap.keys()] or [...myMap.values()].

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Set and Map
Chapter 21 · Page 175
Intermediate

JavaScript Set and Map

(In Practice)
In Practice

Tracking Unique Logins and Frequencies

Processes raw login attempts to return unique user lists and trace login frequencies using Set and Map collections.

  1. 01Deduplicate the list of raw usernames by instantiating a Set collection.
  2. 02Spread the unique set items back into a standard username array.
  3. 03Create a new Map instance to log individual user frequency totals.
  4. 04Iterate through usernames, retrieving previous counts or defaulting to zero.
  5. 05Increment and update the login total for each user in the map.
function analyzeLogins(usernames) {
  const uniqueUsers = [...new Set(usernames)];

  const loginCounts = new Map();
  for (const user of usernames) {
    const count = loginCounts.get(user) ?? 0;
    loginCounts.set(user, count + 1);
  }

  return {
    uniqueUsers,
    loginCounts
  };
}
Takeaway

Use Set for instant value uniqueness checks and Map to associate dynamic values with reference keys.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Spread and Rest
Chapter 22 · Page 176
Intermediate

JavaScript Spread and Rest

Use spread syntax to expand arrays and objects, and rest parameters to handle variable function arguments.

TL;DR

  1. 01Use ... to expand array elements or object properties into context.
  2. 02Gather remaining variables or function arguments using the rest syntax.
  3. 03Ensure rest parameters reside at the end of argument signatures.

Tips

  1. 01Leverage object spread syntax to create shallow copies and merge multiple objects without mutating originals.
  2. 02Combine rest parameters and array destructuring to extract specific list elements and collect the rest.

Warnings

  1. 01Remember that object spread performs a shallow copy, leaving nested object references shared between copies.
  2. 02Placing a rest parameter before other parameters in a function signature throws a SyntaxError.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Spread and Rest
Chapter 22 · Page 177
Intermediate

JavaScript Spread and Rest

(continued)

Spread with Arrays

  • Array merging

    Combines elements of multiple arrays into a new array literal context.

    const arr1 = [1, 2];
    const arr2 = [3, 4];
    const merged = [...arr1, ...arr2]; // [1, 2, 3, 4]
  • Array copy

    Creates a shallow copy of an array, breaking the original reference link.

    const original = [1, 2, 3];
    const copy = [...original];
  • Function arguments

    Expands array items into individual parameters for function execution calls.

    const numbers = [5, 10, 3];
    Math.max(...numbers); // 10
  • Iterable spread

    Converts strings or Sets into arrays using the spread operator.

    const chars = [..."hi"]; // ["h", "i"]
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Spread and Rest
Chapter 22 · Page 178
Intermediate

JavaScript Spread and Rest

(continued)

Spread with Objects

  • Object merging

    Merges property fields of multiple objects into a new object container.

    const user = { name: "Alice", age: 30 };
    const updated = { ...user, active: true };
  • Property override

    Applies new values to keys by placing overrides after the spread target.

    const base = { role: "user", id: 10 };
    const admin = { ...base, role: "admin" };
  • Shallow constraints

    Spreads only top-level fields, leaving nested objects pointing to shared references.

    const obj = { nested: { val: 1 } };
    const copy = { ...obj }; // copy.nested is shared
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Spread and Rest
Chapter 22 · Page 179
Intermediate

JavaScript Spread and Rest

(continued)

Rest Parameters

  • Argument gathering

    Collects excess function arguments into a single standard array handle.

    function sum(...numbers) {
      return numbers.reduce((a, b) => a + b, 0);
    }
  • Named plus rest

    Combines initial named parameters with trailing rest parameter collections.

    function greet(message, ...names) {
      console.log(`${message} ${names.join(", ")}`);
    }
  • Array destructuring

    Gathers remaining array items into a slice list during value assignment.

    const [first, ...rest] = [1, 2, 3, 4];
    // first = 1, rest = [2, 3, 4]
  • Object destructuring

    Extracts target properties while collecting remaining fields in a separate object.

    const { password, ...safeData } = user;
    // password is isolated, rest goes to safeData
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Spread and Rest
Chapter 22 · Page 180
Intermediate

JavaScript Spread and Rest

(continued)

Spread vs Rest

  • Context direction

    Spread expands collections out, while rest collects free elements in.

    const arr = [1, 2];
    const spread = [...arr]; // expands elements
    const [...rest] = arr; // collects elements
  • Usage locations

    Spread occurs in literals and calls; rest occurs in signatures and destructuring.

    Math.min(...[1, 2]); // spread in call
    function test(...args) {} // rest in signature
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Spread and Rest
Chapter 22 · Page 181
Intermediate

JavaScript Spread and Rest

(FAQ)

FAQ

Both features use the ... operator but behave oppositely. Spread expands iterables into separate elements in literals or calls. Rest collects multiple separate elements into a single array structure.

Construct a new object by spreading the sources: { ...obj1, ...obj2 }. If properties overlap, values on the right override properties on the left. This operation only copies own properties.

No, spread performs a shallow copy. If the source contains nested objects, their references are copied rather than duplicate objects. Use structuredClone() to perform a deep clone instead.

Declare a rest parameter: function sum(...nums) { ... }. The rest parameter must sit at the end of the argument list. This compiles arguments into a standard iterable array.

Spread only copies own enumerable properties. Non-enumerable properties and properties inherited from prototypes are bypassed. Use standard accessor methods if you need to fetch inherited properties.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Spread and Rest
Chapter 22 · Page 182
Intermediate

JavaScript Spread and Rest

(In Practice)
In Practice

Immutable Shopping Cart Updates

Updates a specific shopping cart item quantity immutably using object spread syntax to ensure predictable state transitions.

  1. 01Map through the array of items in the cart object.
  2. 02Inspect each item to find the target item ID match.
  3. 03Spread properties of the matching item to construct a new object with updated quantity.
  4. 04Return unmodified items directly to preserve reference identities.
  5. 05Spread the root cart properties, overriding the items list and updating timestamps.
function updateItem(cart, itemId, newQty) {
  const updatedItems = cart.items.map(item => {
    if (item.id !== itemId) return item;
    return {
      ...item,
      quantity: newQty
    };
  });

  return {
    ...cart,
    items: updatedItems,
    updatedAt: Date.now()
  };
}
Takeaway

Utilize object spread to perform non-mutating updates on nested state architectures, maintaining structural sharing in application data.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Timers
Chapter 23 · Page 183
Intermediate

JavaScript Timers

Schedule code execution using setTimeout and setInterval, and rate-limit handlers using debounce and throttle patterns.

TL;DR

  1. 01Schedule delayed or repeating code using setTimeout and setInterval.
  2. 02Cancel pending asynchronous timer callbacks using clear methods.
  3. 03Rate-limit frequent event triggers with debounce and throttle functions.

Tips

  1. 01Always store the timer ID returned by setTimeout or setInterval to cancel execution when conditions change.
  2. 02Prefer requestAnimationFrame over setInterval when creating web animations to match the display refresh rate.

Warnings

  1. 01Remember that timer delays are minimums rather than exact guarantees due to event loop call stack blocking.
  2. 02Forgetting to clear an active setInterval loop creates memory leaks that persist throughout application life.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Timers
Chapter 23 · Page 184
Intermediate

JavaScript Timers

(continued)

setTimeout and clearTimeout

  • setTimeout

    Schedules a single callback execution after a specified millisecond delay.

    setTimeout(() => {
      console.log("Runs after 1 second");
    }, 1000);
  • Timer cancellation

    Cancels a scheduled setTimeout callback before execution using its timer ID.

    const id = setTimeout(() => console.log("done"), 5000);
    clearTimeout(id);
  • Forwarding arguments

    Passes extra arguments directly into the timer callback function handler.

    setTimeout(u => console.log(u), 1000, "Alice");
  • Zero delay

    Queues a callback at the end of the current execution stack immediately.

    console.log("first");
    setTimeout(() => console.log("third"), 0);
    console.log("second");
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Timers
Chapter 23 · Page 185
Intermediate

JavaScript Timers

(continued)

setInterval and clearInterval

  • setInterval

    Schedules repeated callback execution on a fixed time interval loop.

    const id = setInterval(() => {
      console.log("tick");
    }, 1000);
  • Self-clearing interval

    Stops a repeating interval internally once a counter threshold is met.

    let count = 0;
    const id = setInterval(() => {
      count++;
      if (count >= 5) clearInterval(id);
    }, 1000);
  • Poller cleanups

    Clears active poll intervals during cleanups to prevent resource leaks.

    function poll() {
      const id = setInterval(fetchData, 5000);
      return () => clearInterval(id); // clean
    }
  • Recursive timeout

    Chains setTimeouts recursively to ensure steady spacing between variable runs.

    function poll() {
      doWork();
      setTimeout(poll, 1000);
    }
    poll();
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Timers
Chapter 23 · Page 186
Intermediate

JavaScript Timers

(continued)

Timer Precision and Event Loop

  • Main thread blocks

    Timers await thread clearance, causing late execution if synchronous blocks run.

    setTimeout(() => console.log("late"), 0);
    while (Date.now() < start + 200) {} // block
  • Sequential queueing

    Long synchronous execution blocks delay all queued callbacks concurrently.

    setTimeout(() => console.log("A"), 10);
    setTimeout(() => console.log("B"), 20);
    // delayed together if thread is busy
  • Macrotask queueing

    Timers run as macrotasks, resolving after synchronous code and microtasks.

    console.log("1");
    setTimeout(() => console.log("3"), 0);
    Promise.resolve().then(() => console.log("2"));
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Timers
Chapter 23 · Page 187
Intermediate

JavaScript Timers

(continued)

Debounce and Throttle

  • Debounce helper

    Delays function execution, resetting the timer on each new invocation.

    function debounce(fn, delay) {
      let id;
      return (...args) => {
        clearTimeout(id);
        id = setTimeout(() => fn(...args), delay);
      };
    }
  • Input search

    Limits API fetch queries by triggering only after typing pauses.

    const search = debounce(query => fetch(query), 300);
    input.addEventListener("input", e => {
      search(e.target.value);
    });
  • Throttle helper

    Executes a function at most once per fixed time interval window.

    function throttle(fn, limit) {
      let wait = false;
      return (...args) => {
        if (wait) return;
        fn(...args);
        wait = true;
        setTimeout(() => { wait = false; }, limit);
      };
    }
  • Scroll tracking

    Protects browser scroll listeners from triggering expensive paint redraws.

    const logScroll = throttle(() => updateUI(), 200);
    window.addEventListener("scroll", logScroll);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Timers
Chapter 23 · Page 188
Intermediate

JavaScript Timers

(continued)

requestAnimationFrame

  • rAF animation loop

    Schedules callbacks right before the browser repaints active screen elements.

    function animate() {
      moveElement();
      requestAnimationFrame(animate);
    }
    requestAnimationFrame(animate);
  • Animation stop

    Terminates a requestAnimationFrame animation loop using the returned ID.

    const id = requestAnimationFrame(animate);
    cancelAnimationFrame(id);
  • Scroll sync

    Synchronizes visual adjustments directly with browser repaint refresh frames.

    let ticking = false;
    window.addEventListener("scroll", () => {
      if (!ticking) {
        requestAnimationFrame(() => {
          updateScroll();
          ticking = false;
        });
        ticking = true;
      }
    });
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Timers
Chapter 23 · Page 189
Intermediate

JavaScript Timers

(FAQ)

FAQ

JavaScript runs on a single thread. The event loop cannot run timer callbacks until the call stack is empty. Long synchronous tasks block the queue and delay timer execution.

Debouncing waits for a pause in events before running a function once. Throttling limits execution to at most once per fixed time interval. Use debouncing for search input and throttling for scrolling.

No, setTimeout callbacks remove themselves from the event queue automatically after running. You only need to call clearTimeout to cancel a pending timer before it executes.

The requestAnimationFrame method coordinates callbacks with display refresh rates, creating smoother motion. It also pauses automatically when browser tabs become inactive. This saves battery and processor power.

No, the browser prevents concurrent execution by waiting for the thread to clear. However, callbacks can queue up and fire rapidly in succession. Use recursive setTimeout for regular spacing instead.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Timers
Chapter 23 · Page 190
Intermediate

JavaScript Timers

(In Practice)
In Practice

Search Debouncer with Resource Cleanup

Creates a search debouncer that delays query submissions and offers a cleanup method to prevent memory leaks.

  1. 01Establish a local variable to store the active timer identifier.
  2. 02Clear any pending search timeouts upon receiving new user key inputs.
  3. 03Schedule a new timeout handler to submit queries after three hundred milliseconds.
  4. 04Define a destroy function to cancel any outstanding timers during unmounting.
  5. 05Return the event handler and cleanup callbacks to the caller.
function createSearchInput(onSearch) {
  let timerId;

  function handleInput(event) {
    clearTimeout(timerId);
    const query = event.target.value;

    timerId = setTimeout(() => {
      onSearch(query);
    }, 300);
  }

  function destroy() {
    clearTimeout(timerId);
  }

  return { handleInput, destroy };
}
Takeaway

Implement debouncing to rate-limit expensive api requests, and always clean up timers to prevent application memory leaks.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Type Coercion
Chapter 24 · Page 191
Intermediate

JavaScript Type Coercion

Understand how JavaScript converts types automatically and avoid common equality and comparison bugs.

TL;DR

  1. 01Compare values with strict === to prevent implicit coercion.
  2. 02Identify truthy and falsy variables inside conditional blocks.
  3. 03Convert data types explicitly using Number, String, or Boolean.

Tips

  1. 01Always use strict comparison operators to prevent JavaScript from silently converting types behind your back.
  2. 02Convert numeric values explicitly using the standard Number() constructor to ensure clean mathematical operations.

Warnings

  1. 01Remember that empty arrays and objects evaluate as truthy values inside conditional expressions.
  2. 02Adding numbers and strings triggers implicit string concatenation instead of expected arithmetic addition.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Type Coercion
Chapter 24 · Page 192
Intermediate

JavaScript Type Coercion

(continued)

Loose vs Strict Equality

  • Strict equality

    Compares values and types directly with zero implicit conversion.

    console.log(1 === 1);   // true
    console.log(1 === "1"); // false
  • Loose equality

    Converts operand types automatically before comparing values.

    console.log(1 == "1");  // true
    console.log(0 == false); // true
  • Nullish checks

    Uses loose equality to check for both null and undefined variables at once.

    function isMissing(v) {
      return v == null;
    }
  • NaN comparison

    Uses Number.isNaN because NaN never equals itself under comparison.

    console.log(NaN === NaN); // false
    console.log(Number.isNaN(NaN)); // true
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Type Coercion
Chapter 24 · Page 193
Intermediate

JavaScript Type Coercion

(continued)

Truthy and Falsy Values

  • Falsy list

    Lists all eight falsy values which evaluate to false in boolean contexts.

    const falsy = [
      false, 0, -0, 0n, "", null, undefined, NaN
    ];
  • Empty collections

    Verifies that empty arrays and objects evaluate as truthy.

    if ([]) console.log("runs"); // true
    if ({}) console.log("runs"); // true
  • Length verification

    Checks array lengths explicitly rather than relying on list truthiness.

    const list = [];
    if (list.length === 0) {
      console.log("empty");
    }
  • Double negation

    Coerces values into strict booleans using two logical NOT operators.

    console.log(!!"text"); // true
    console.log(!!0);      // false
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Type Coercion
Chapter 24 · Page 194
Intermediate

JavaScript Type Coercion

(continued)

Implicit Conversion

  • String concatenation

    Converts numbers to strings when executing addition with string operands.

    console.log(1 + "1"); // "11"
    console.log("a" + 1); // "a1"
  • Numeric coercion

    Coerces string values to numbers when using subtraction or division operators.

    console.log("5" - 2); // 3
    console.log("5" * "2"); // 10
  • Relational operators

    Converts strings to numbers during numeric comparison evaluation checks.

    console.log("10" > 5); // true
  • Template interpolation

    Coerces embedded variables to strings inside template literal strings.

    const age = 30;
    console.log(`Age: ${age}`); // "Age: 30"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Type Coercion
Chapter 24 · Page 195
Intermediate

JavaScript Type Coercion

(continued)

Explicit Conversion

  • Boolean()

    Converts any variable type into a true or false boolean value.

    Boolean("");  // false
    Boolean("0"); // true (non-empty)
  • Number()

    Parses strings or values into numbers, returning NaN on invalid characters.

    Number("42");  // 42
    Number("abc"); // NaN
  • String()

    Converts numbers, null, or undefined values into matching literal strings.

    String(42);   // "42"
    String(null); // "null"
  • parseInt()

    Parses numbers from strings with trailing non-numeric characters.

    parseInt("42px", 10); // 42
    Number("42px");       // NaN
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Type Coercion
Chapter 24 · Page 196
Intermediate

JavaScript Type Coercion

(FAQ)

FAQ

Loose equality == converts operand types before comparison. Strict equality === compares values and types directly. Strict equality is recommended to avoid unpredictable conversion bugs.

Loose equality coerces both operands toward numbers. The empty array converts to an empty string, then to zero. The boolean false also becomes zero. Since both evaluate to zero, they match.

Falsy values are false, 0, -0, 0n, empty strings, null, undefined, and NaN. All other values are truthy. This includes empty arrays, empty objects, and the string '0'.

The plus operator triggers string concatenation if either operand is a string. JavaScript converts the number to a string and links them. Use subtraction or explicit conversion to do math.

Do not use equality operators, because NaN never equals anything, including itself. Use the Number.isNaN() method instead. This method correctly determines if a value is not a number.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Type Coercion
Chapter 24 · Page 197
Intermediate

JavaScript Type Coercion

(In Practice)
In Practice

Validating Numeric Form Input

Converts raw form inputs explicitly to process user ages, avoiding implicit coercion bugs and checking for NaN failures.

  1. 01Convert the input value to a string explicitly and trim surrounding whitespace.
  2. 02Verify that the cleaned string is not empty before parsing.
  3. 03Coerce the string to a number using the explicit Number constructor.
  4. 04Check if the resulting number is NaN to detect invalid input characters.
  5. 05Return the verified number or a fallback null value.
function processAgeInput(inputValue) {
  const cleanString = String(inputValue).trim();
  if (!cleanString) return null;

  const parsedNumber = Number(cleanString);
  if (Number.isNaN(parsedNumber)) return null;

  return parsedNumber;
}
Takeaway

Always use explicit conversion methods and verify values with Number.isNaN() to prevent numeric comparison failures.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async Iterators
Chapter 25 · Page 198
Advanced

JavaScript Async Iterators

Learn async iterators, async generators, and for await...of for consuming asynchronous data lazily.

TL;DR

  1. 01Yield promises that resolve to { value, done } via async iterators.
  2. 02Build async generators with async function* to yield values lazily.
  3. 03Consume async iterables with for await...of as values arrive.

Tips

  1. 01Use async generators to wrap paginated APIs, so callers loop over pages without managing cursors manually.
  2. 02Prefer for await...of over manually calling next() when consuming streams — it awaits values and cleans up automatically.

Warnings

  1. 01Awaiting each next() call sequentially means items resolve one at a time, not all at once.
  2. 02Forgetting that for await...of also works on plain, synchronous iterables can confuse debugging of sequential async behavior.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async Iterators
Chapter 25 · Page 199
Advanced

JavaScript Async Iterators

(continued)

What Async Iterators Are

  • Symbol.asyncIterator

    `next()` returns a Promise resolving to `{ value, done }`, not a plain object.

    const asyncIt = {
      [Symbol.asyncIterator]() {
        let i = 0;
        return {
          next: () =>
            Promise.resolve(
              { value: i++, done: i > 3 }
            )
        };
      }
    };
  • Class-based iterable

    A class implements async iteration by returning `this` from `[Symbol.asyncIterator]()`.

    class Logs {
      constructor(lines) {
        this.i = 0;
        this.lines = lines;
      }
      [Symbol.asyncIterator]() { return this; }
      next() {
        const done = this.i >= this.lines.length;
        const value = this.lines[this.i++];
        return Promise.resolve({ value, done });
      }
    }
  • Dual protocols

    An object can implement `Symbol.iterator` and `Symbol.asyncIterator` for two iteration modes.

    const range = {
      [Symbol.iterator]() {
        let i = 0;
        return {
          next: () => ({ value: i++, done: i > 2 })
        };
      },
      [Symbol.asyncIterator]() {
        let i = 0;
        return {
          next: () => Promise.resolve(
            { value: i++, done: i > 2 }
          )
        };
      }
    };
  • Manual next() calls

    Call `next()` directly and `await` each promise to drive iteration by hand.

    async function drain(it) {
      let result = await it.next();
      while (!result.done) {
        console.log(result.value);
        result = await it.next();
      }
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async Iterators
Chapter 25 · Page 200
Advanced

JavaScript Async Iterators

(continued)

Async Generator Functions

  • async function*

    Declare an async generator by combining `await` and `yield` in one body.

    async function* fetchPages(url) {
      let next = url;
      while (next) {
        const res = await fetch(next);
        const page = await res.json();
        yield page.items;
        next = page.nextUrl;
      }
    }
  • yield pauses

    Each `yield` suspends the generator until the caller requests the next value.

    async function* ticker() {
      console.log('start');
      yield 1;
      console.log('resumed');
      yield 2;
    }
    const t = ticker();
    await t.next(); // logs 'start'
    await t.next(); // logs 'resumed'
  • Returns an iterable

    Calling an async generator returns an async iterable right away; the body waits.

    async function* slow() {
      console.log('running');
      yield 1;
    }
    const gen = slow(); // logs nothing yet
    await gen.next();   // now logs 'running'
  • Error propagation

    An error thrown inside the generator rejects the promise `next()` returns.

    async function* risky() {
      yield 1;
      throw new Error('boom');
    }
    try {
      for await (const v of risky()) {
        console.log(v);
      }
    } catch (e) {
      console.log(e.message); // 'boom'
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async Iterators
Chapter 25 · Page 201
Advanced

JavaScript Async Iterators

(continued)

The for await...of Loop

  • for await...of

    Consume an async iterable with `for await...of`, awaiting each value automatically.

    async function run() {
      for await (const items of
        fetchPages('/api/items')) {
        console.log(items);
      }
    }
  • Waits per iteration

    The loop body only runs once the currently yielded promise resolves.

    async function* slowNums() {
      yield 1;
      await new Promise(r => setTimeout(r, 100));
      yield 2;
    }
    for await (const n of slowNums()) {
      console.log(Date.now(), n);
    }
  • Scope restriction

    `for await...of` only works inside an async function or a module's top level.

    async function readAll(stream) {
      for await (const chunk of stream) {
        process(chunk);
      }
    }
  • Accepts sync too

    It also accepts plain, synchronous iterables, awaiting each value for consistency.

    for await (const n of [1, 2, 3]) {
      console.log(n);
    }
    // logs: 1 2 3
  • Cleanup on exit

    `break` or `return` inside the loop runs the generator's `finally` block for cleanup.

    async function* withCleanup() {
      try {
        yield 1;
        yield 2;
      } finally {
        console.log('cleanup');
      }
    }
    for await (const n of withCleanup()) {
      if (n === 1) break;
    }
    // logs 'cleanup' after break
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async Iterators
Chapter 25 · Page 202
Advanced

JavaScript Async Iterators

(continued)

Consuming Streams and Paginated APIs

  • Wrap the endpoint

    Wrap a paginated endpoint in an async generator so callers never see cursor logic.

    async function* paginate(fetchPage) {
      let cursor = null;
      do {
        const { items, nextCursor } =
          await fetchPage(cursor);
        yield* items;
        cursor = nextCursor;
      } while (cursor);
    }
  • yield* delegation

    `yield*` unpacks an iterable and emits each item, instead of one array.

    async function* asPage() {
      yield [1, 2, 3];
    }
    async function* asItems() {
      yield* [1, 2, 3];
    }
    // asPage yields one array
    // asItems yields 1, then 2, then 3
  • Lazy evaluation

    Pages fetch only when consumed; `break` stops further fetches and keeps memory flat.

    let pagesFetched = 0;
    async function* lazyPages() {
      while (true) {
        pagesFetched++;
        yield pagesFetched;
      }
    }
    for await (const page of lazyPages()) {
      if (page === 2) break;
    }
    console.log(pagesFetched); // 2, not more
  • Native stream support

    Node.js Readable streams implement `Symbol.asyncIterator` natively, so they work here.

    for await (const chunk of
      fs.createReadStream('file.txt')) {
      console.log(chunk.length);
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async Iterators
Chapter 25 · Page 203
Advanced

JavaScript Async Iterators

(continued)

Async vs Sync Iteration

  • Sync vs async generator

    A sync generator yields values directly; an async one yields promises that resolve.

    function* syncGen() { yield 1; yield 2; }
    async function* asyncGen() {
      yield 1;
      yield 2;
    }
  • Matching loop

    Plain `for...of` cannot read an async iterable; it needs `for await...of` to unwrap values.

    for (const x of asyncGen()) {}
    // TypeError: not a function or its
    // return value is not iterable
    
    for await (const x of asyncGen()) {
      console.log(x); // 1, then 2
    }
  • Spread limitation

    Spread syntax (`...`) only works with sync iterables; it cannot await an async one.

    console.log([...asyncGen()]);
    // TypeError: not a function or its
    // return value is not iterable
  • await alone isn't enough

    Adding `await` inside a plain `function*` is a syntax error; use `async function*`.

    function* broken() {
      yield 1;
      await Promise.resolve(2);
      // SyntaxError: await is only
      // valid in async functions
    }
  • Converting sync to async

    Wrap a sync iterable in an async generator, awaiting each value as it's yielded.

    async function* toAsync(iterable) {
      for (const value of iterable) {
        yield await Promise.resolve(value);
      }
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async Iterators
Chapter 25 · Page 204
Advanced

JavaScript Async Iterators

(FAQ)

FAQ

Symbol.iterator defines a synchronous iterator whose next() returns {value, done} directly. Symbol.asyncIterator defines an async iterator whose next() returns a Promise that resolves to {value, done}. Use the async version whenever producing a value requires waiting, like a network request.

Combine the async and function* keywords into async function*. Inside it, use await for asynchronous work and yield to emit values. Calling it returns an async iterable you can loop over with for await...of.

Use for await...of when looping over an async iterable, such as an async generator or a stream of paginated results. It automatically awaits each yielded promise before running the loop body. A regular for...of loop cannot await values produced asynchronously.

Yes — for await...of works with any iterable, sync or async, and awaits each value automatically. Given an array of promises, it awaits each one in order before continuing. This makes it useful for processing a fixed list of pending requests sequentially.

An async generator can fetch one page, yield its items, then fetch the next page only when asked. This keeps memory usage low since pages load lazily instead of all at once. Callers just loop with for await...of and never see the pagination logic.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Async Iterators
Chapter 25 · Page 205
Advanced

JavaScript Async Iterators

(In Practice)
In Practice

Streaming Paginated Search Results

An async generator lazily fetches pages of search results, and for await...of stops as soon as a match is found.

  1. 01fetchResults is an async generator that fetches one page of results at a time.
  2. 02yield* items emits each item individually instead of yielding whole page arrays.
  3. 03for await...of automatically awaits each yielded item before running the loop body.
  4. 04Returning early from the loop stops fetching further pages the caller no longer needs.
async function* fetchResults(query) {
  let cursor = null;
  do {
    const res = await fetch(`/api/search?q=${query}&cursor=${cursor ?? ''}`);
    const { items, nextCursor } = await res.json();
    yield* items;
    cursor = nextCursor;
  } while (cursor);
}

async function findFirstMatch(query, predicate) {
  for await (const item of fetchResults(query)) {
    if (predicate(item)) return item;
  }
  return null;
}

const match = await findFirstMatch('laptop', item => item.price < 500);
console.log(match);
// stops fetching pages as soon as a match is found
Takeaway

Async generators plus for await...of stream results lazily — you only fetch as many pages as you actually need.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Call Apply Bind
Chapter 26 · Page 206
Advanced

JavaScript Call Apply Bind

Control the this keyword explicitly using call, apply, and bind on any function.

TL;DR

  1. 01call() and apply() invoke a function with a chosen this value.
  2. 02apply() takes arguments as an array; call() takes a list.
  3. 03bind() returns a new function with this permanently fixed.

Tips

  1. 01Use bind() when passing a method as a callback or event handler, so this stays correct.
  2. 02Reach for apply() when arguments already exist as an array, such as forwarding arguments between wrapper functions.

Warnings

  1. 01Calling bind() repeatedly on the same function creates a new wrapper each time, which breaks reference equality checks like removeEventListener.
  2. 02Arrow functions ignore call, apply, and bind for this, since arrow functions always inherit this from their enclosing scope.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Call Apply Bind
Chapter 26 · Page 207
Advanced

JavaScript Call Apply Bind

(continued)

Why this Needs Explicit Control

  • Call site matters

    The value of this depends on how a function is called, not where it's defined.

    const user = { name: 'Ada', greet() { return `Hi, ${this.name}`; } };
    const fn = user.greet;
    fn(); // 'Hi, undefined' — this lost its connection to user
  • Detached methods

    Passing a method as a value, like a callback, detaches it from its original object.

  • Explicit control

    call, apply, and bind exist to set this explicitly regardless of call site.

  • Function.prototype

    All three live on Function.prototype, so every function has access to them.

  • Common breakage

    Without explicit control, callbacks and event handlers commonly break on this.

  • Legacy code

    Understanding these three methods is essential for working with older, non-arrow-function code.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Call Apply Bind
Chapter 26 · Page 208
Advanced

JavaScript Call Apply Bind

(continued)

Using call()

  • call(thisArg, ...args)

    Invoke a function immediately with arguments listed individually.

    function greet(greeting) { return `${greeting}, ${this.name}`; }
    greet.call({ name: 'Ada' }, 'Hi'); // 'Hi, Ada'
  • First argument is this

    The first argument becomes this inside the function for that one call.

  • Positional arguments

    Remaining arguments map positionally to the function's parameters.

  • Borrowing methods

    Use call() to borrow a method from one object and run it against another.

    const max = Math.max.call(null, 1, 5, 3); // 5
  • null or undefined

    Passing null or undefined as thisArg uses the global object in non-strict mode.

  • Single invocation only

    call() does not change the original function; it only affects that single invocation.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Call Apply Bind
Chapter 26 · Page 209
Advanced

JavaScript Call Apply Bind

(continued)

Using apply()

  • apply(thisArg, argsArray)

    Works exactly like call(), but arguments are passed as one array.

    function sum(a, b, c) { return a + b + c; }
    sum.apply(null, [1, 2, 3]); // 6
  • Array-like arguments

    apply() is the better choice when arguments already exist as an array or array-like.

    Math.max.apply(null, [4, 8, 2]); // 8
  • Spread replaces it

    Modern code often replaces apply() with the spread operator: Math.max(...nums).

  • Forwarding arguments

    apply() still matters when forwarding an arguments object between functions.

  • Synchronous return

    Both call() and apply() execute the function synchronously and return its result.

  • Choosing between them

    Choosing between call and apply is purely about argument shape — list versus array.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Call Apply Bind
Chapter 26 · Page 210
Advanced

JavaScript Call Apply Bind

(continued)

Using bind()

  • bind(thisArg)

    Creates a new function with this permanently fixed to the given value.

    const user = { name: 'Ada', greet() { return `Hi, ${this.name}`; } };
    const boundGreet = user.greet.bind(user);
    boundGreet(); // 'Hi, Ada' — works even detached from user
  • Doesn't invoke

    Unlike call() and apply(), bind() does not invoke the function immediately.

  • Store for later

    The returned function can be stored, passed around, and called later safely.

  • Bind in constructors

    Bind methods in a constructor so they keep this when used as callbacks.

    class Button {
      constructor() { this.onClick = this.onClick.bind(this); }
      onClick() { console.log(this); }
    }
  • Fixed permanently

    Calling bind() again on an already-bound function cannot change its fixed this.

  • Bound function names

    Bound functions report 'bound functionName' when inspected, which helps when debugging.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Call Apply Bind
Chapter 26 · Page 211
Advanced

JavaScript Call Apply Bind

(continued)

Partial Application with bind

  • Prepended arguments

    Arguments passed to bind() after thisArg get permanently prepended to every future call.

    function multiply(a, b) { return a * b; }
    const double = multiply.bind(null, 2);
    double(5); // 10
  • Partial application

    This technique is called partial application, fixing some arguments ahead of time.

  • Event handler context

    Combine partial application with event handlers to pass extra context cleanly.

    button.addEventListener('click', handleClick.bind(null, itemId));
  • Extra arguments still work

    Partially applied functions still accept additional arguments at call time.

  • Specialized utilities

    Use partial application to build specialized utility functions from general ones.

  • Avoids wrappers

    This pattern avoids writing repetitive wrapper functions for common argument combinations.

Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Call Apply Bind
Chapter 26 · Page 212
Advanced

JavaScript Call Apply Bind

(FAQ)

FAQ

Both invoke a function immediately with a specified this value. call() takes the function's arguments individually, separated by commas. apply() takes them bundled into a single array. They behave identically once the arguments are in place.

call() and apply() invoke the function right away. bind() does not call the function; it returns a new function with this permanently set. You call that returned function later, optionally with more arguments.

When a method is passed as a callback, like onClick={this.handleClick}, it loses its connection to the instance. Calling it later sets this to undefined or the global object instead of the instance. Binding it in the constructor, or using an arrow function class field, fixes this permanently.

Yes, this is called partial application. Any arguments passed to bind() after the this value get permanently prepended to future calls. For example, multiply.bind(null, 2) returns a function that always doubles its input.

Calling bind() on an arrow function has no effect on this, because arrow functions never have their own this. You can still bind arguments for partial application, but the this value stays whatever it was lexically. Use a regular function if you need bind() to control this.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Call Apply Bind
Chapter 26 · Page 213
Advanced

JavaScript Call Apply Bind

(In Practice)
In Practice

Formatting Log Messages with call() and bind()

call() borrows a shared formatter for different log entries, while bind() creates reusable, prefixed logger functions.

  1. 01format() reads this.level and this.message, so call() supplies a different object as this each time.
  2. 02Passing 'API' as the second call() argument fills the prefix parameter for that one invocation.
  3. 03log.bind(null, 'API') permanently fixes the prefix argument, returning a reusable specialized function.
  4. 04apiLog can still be called later with the remaining level and message arguments.
function format(prefix) {
  return `[${prefix}] ${this.level}: ${this.message}`;
}

const errorEntry = { level: 'ERROR', message: 'Connection lost' };
const infoEntry = { level: 'INFO', message: 'Server started' };

console.log(format.call(errorEntry, 'API')); // '[API] ERROR: Connection lost'
console.log(format.call(infoEntry, 'API'));  // '[API] INFO: Server started'

function log(prefix, level, message) {
  console.log(`[${prefix}] ${level}: ${message}`);
}

const apiLog = log.bind(null, 'API');
apiLog('WARN', 'Rate limit approaching');
// '[API] WARN: Rate limit approaching'
Takeaway

call() sets this for a single invocation, while bind() locks in this and arguments for reuse.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Closures
Chapter 27 · Page 214
Advanced

JavaScript Closures

Understand how closures allow inner functions to retain access to variables from parent scopes with examples.

TL;DR

  1. 01Ensure inner functions retain access to their defining parent scopes.
  2. 02Store persistent private data state safely without using global variables.
  3. 03Resolve outer variables based on where functions are statically defined.

Tips

  1. 01Expose public API methods while keeping raw state hidden inside an enclosing closure scope function.
  2. 02Choose closures over standard class definitions when you only need to store small private states.

Warnings

  1. 01Avoid creating unnecessary closures enclosing huge objects because they can generate substantial memory leaks.
  2. 02Declare loop indexes using let so that each iteration receives its own distinct variable binding.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Closures
Chapter 27 · Page 215
Advanced

JavaScript Closures

(continued)

What Closures Are

  • Closure definition

    Keeps reference access to outer scope variables even after parent execution finishes.

    function outer() {
      let n = 0;
      return () => ++n;
    }
    const count = outer();
    count(); // 1
  • Scope nesting

    Forms closures automatically whenever you nest child functions inside parent contexts.

    function parent() {
      const x = 1;
      function child() { return x; }
    }
  • Memory persistence

    Retains outer scope values in memory as long as the child function exists.

    const fn = outer(); // n stays in memory
  • Lexical scope

    Resolves variable scopes statically based on where the functions are declared.

    const x = 10;
    function test() { console.log(x); }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Closures
Chapter 27 · Page 216
Advanced

JavaScript Closures

(continued)

Closures and Loops

  • var in loop

    Shares a single variable reference across all loop callbacks, causing bugs.

    for (var i = 0; i < 3; i++) {
      setTimeout(() => console.log(i));
    }
    // logs 3, 3, 3
  • let in loop

    Creates a new variable binding block per loop iteration to fix sharing.

    for (let i = 0; i < 3; i++) {
      setTimeout(() => console.log(i));
    }
    // logs 0, 1, 2
  • IIFE capture

    Caps variable values per iteration loop by wrapping functions in IIFE scopes.

    for (var i = 0; i < 3; i++) {
      (v => setTimeout(() => console.log(v)))(i);
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Closures
Chapter 27 · Page 217
Advanced

JavaScript Closures

(continued)

Private Variables

  • State encapsulation

    Stores internal variable values safely away from the global execution context.

    function createCounter() {
      let count = 0;
      return {
        increment: () => ++count,
        get: () => count
      };
    }
  • Public API access

    Exposes interface methods to read and write private variables under control.

    const c = createCounter();
    c.increment();
    console.log(c.get()); // 1
  • Accidental mutation

    Prevents external script scripts from corrupting or writing internal state values directly.

    let c = createCounter();
    // c.count is undefined
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Closures
Chapter 27 · Page 218
Advanced

JavaScript Closures

(continued)

Function Factories

  • Behavior configuration

    Creates functions sharing standard behaviors but retaining distinct internal configurations.

    function makeAdder(x) {
      return y => x + y;
    }
    const add5 = makeAdder(5);
    add5(10); // 15
  • Private memoization

    Closes over a private Map cache to return cached function outputs.

    function memoize(fn) {
      const cache = new Map();
      return x => {
        if (cache.has(x)) return cache.get(x);
        const res = fn(x);
        cache.set(x, res);
        return res;
      };
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Closures
Chapter 27 · Page 219
Advanced

JavaScript Closures

(FAQ)

FAQ

Closures inside a var loop share one variable reference. The loop terminates before the callbacks execute. Change the declaration to let to bind a fresh variable index per iteration.

Declare local variables inside a parent function and return helper functions accessing them. The returned helpers close over the state. External operations cannot inspect or alter this private state directly.

A function becomes a closure when it references variables outside its scope after the parent context exits. The closure keeps these external variables alive in memory. Normal functions only use parameters.

A factory function accepts configuration values and returns specialized functions enclosing those values. For example, makeAdder(5) returns a helper that always adds five. This keeps logic parameterized and clean.

Avoid capturing large object references that you do not need. Destructure only specific values required by the inner function. Nullify large variable handles once they are no longer needed.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Closures
Chapter 27 · Page 220
Advanced

JavaScript Closures

(In Practice)
In Practice

Debouncing Input with Closures

A debounce factory function closes over a timer reference to ensure that rapid handlers only execute once typing pauses.

  1. 01Declare a local variable to hold the active timeout identifier.
  2. 02Return a closure function that accepts arguments and intercepts calls.
  3. 03Clear any existing scheduled timeout to cancel the previous call.
  4. 04Schedule a new timeout to execute the target function after a delay.
  5. 05Forward the function arguments to the target handler on execution.
function debounce(fn, delay) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn(...args);
    }, delay);
  };
}
Takeaway

The closure over the timer variable keeps it alive between calls without polluting the global variable namespace.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Currying and Composition
Chapter 28 · Page 221
Advanced

JavaScript Currying and Composition

Transform multi-argument functions into chained calls and combine small functions into pipelines.

TL;DR

  1. 01Transform multi-argument functions into nested single-argument curry functions.
  2. 02Apply subset arguments up front to generate specialized function presets.
  3. 03Compose independent single-input operations into clean linear data pipelines.

Tips

  1. 01Design small, single-purpose functions to make currying and function composition patterns easier to build.
  2. 02Prefer the pipe helper to construct left-to-right processing streams matching natural reading orders.

Warnings

  1. 01Avoid currying every simple method because unnecessary function wrappers hurt overall script readability.
  2. 02Validate data parameters at each pipeline step to prevent silent runtime type errors.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Currying and Composition
Chapter 28 · Page 222
Advanced

JavaScript Currying and Composition

(continued)

What Currying Does

  • Currying chains

    Converts multi-argument functions into sequential single-argument calls.

    function add(a, b, c) {
      return a + b + c;
    }
    const curryAdd = a => b => c => a + b + c;
    curryAdd(1)(2)(3); // 6
  • Call execution

    Invokes the original function only after all arguments are received.

    const add5 = curryAdd(5);
    add5(2)(3); // 10
  • Arrow notation

    Uses nested arrow functions to construct inline curried definitions.

    const multiply = a => b => a * b;
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Currying and Composition
Chapter 28 · Page 223
Advanced

JavaScript Currying and Composition

(continued)

A Generic Curry Helper

  • curry() implementation

    Gathers arguments recursively until the count matches function arity.

    function curry(fn) {
      return function curried(...args) {
        if (args.length >= fn.length) {
          return fn.apply(this, args);
        }
        return (...next) => {
          return curried.apply(this, [...args, ...next]);
        };
      };
    }
  • Function length

    Resolves function arity dynamically using the fn.length property.

    const sum = curry((a, b, c) => a + b + c);
    sum(1)(2)(3); // 6
    sum(1, 2)(3); // 6
  • Arity configurations

    Specifies manual arity limits for functions with default parameters.

    function curryN(fn, arity) {
      return function collect(...args) {
        return args.length >= arity
          ? fn(...args)
          : (...more) => collect(...args, ...more);
      };
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Currying and Composition
Chapter 28 · Page 224
Advanced

JavaScript Currying and Composition

(continued)

Partial Application

  • bind() method

    Binds arguments up front using the built-in prototype bind method.

    function mult(a, b) { return a * b; }
    const double = mult.bind(null, 2);
    double(5); // 10
  • Custom partial

    Builds a partial helper to bind arguments without bind context.

    function partial(fn, ...fixed) {
      return (...rest) => fn(...fixed, ...rest);
    }
    const greet = partial((g, n) => g + n, "Hi ");
    greet("Ada"); // "Hi Ada!"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Currying and Composition
Chapter 28 · Page 225
Advanced

JavaScript Currying and Composition

(continued)

Composing Functions

  • compose() helper

    Combines functions executing right-to-left like mathematical equations.

    const compose = (...fns) => x =>
      fns.reduceRight((acc, f) => f(acc), x);
    const shout = s => s.toUpperCase() + "!";
    const format = compose(shout, s => s.trim());
    format("  hi  "); // "HI!"
  • pipe() helper

    Combines functions executing left-to-right to match reading order.

    const pipe = (...fns) => x =>
      fns.reduce((acc, f) => f(acc), x);
    const run = pipe(s => s.trim(), s => s.toUpperCase());
    run("  hi  "); // "HI"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Currying and Composition
Chapter 28 · Page 226
Advanced

JavaScript Currying and Composition

(continued)

Practical Use Cases

  • Curried validation

    Pre-fills validation parameters to generate specialized rule checklists.

    const minLength = curry((min, s) => s.length >= min);
    const isValid = minLength(3);
    isValid("ok"); // false
  • Middleware execution

    Threads orders or values through sequential modifier function lists.

    const processOrder = pipe(
      applyDiscount,
      addTax
    );
    processOrder(100);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Currying and Composition
Chapter 28 · Page 227
Advanced

JavaScript Currying and Composition

(FAQ)

FAQ

Currying transforms a function to accept one argument per call sequentially. Partial application binds multiple arguments immediately and returns a function waiting for the remaining parameters.

Inspect target function arity using the length property. Recursively gather arguments until they match or exceed that length, then invoke the underlying function.

Both helpers chain functions together. Compose executes functions from right to left. Pipe executes them from left to right, matching sequential reading order.

Currying enables specialized helper construction by pre-filling configuration values. This reduces duplicate parameters and allows seamless integration inside pipeline composition chains.

Curried calls instantiate closure environments and nested calls. The performance cost is usually negligible. Avoid currying inside critical performance paths like tight execution loops.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Currying and Composition
Chapter 28 · Page 228
Advanced

JavaScript Currying and Composition

(In Practice)
In Practice

Order Processing Pipeline

Pairs a curried discount calculator with a left-to-right pipeline to process invoice figures.

  1. 01Write a generic currying helper to allow step-by-step argument input.
  2. 02Curry the discount calculation function and fix the percentage rate.
  3. 03Define standard tax and currency formatting math operations.
  4. 04Pipe the functions together to thread inputs through each step sequentially.
  5. 05Invoke the completed pipeline with a test order price.
const curry = fn => (...args) =>
  args.length >= fn.length
    ? fn(...args)
    : (...more) => curry(fn)(...args, ...more);

const applyDiscount = curry((rate, price) =>
  price * (1 - rate)
);
const applyTenPercentOff = applyDiscount(0.1);
const addTax = price => price * 1.08;
const format = price => "$" + price.toFixed(2);

const pipe = (...fns) => x =>
  fns.reduce((acc, fn) => fn(acc), x);

const processOrder = pipe(
  applyTenPercentOff,
  addTax,
  format
);

console.log(processOrder(100)); // "$97.20"
Takeaway

Pre-filling function parameters with currying yields simple unary steps that pipe links together smoothly.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Event Loop
Chapter 29 · Page 229
Advanced

JavaScript Event Loop

Learn how the call stack, microtask queue, and task queue control JavaScript execution order.

TL;DR

  1. 01The call stack executes synchronous code one frame at a time.
  2. 02Microtasks execute immediately after the current stack frame completes.
  3. 03Promises resolve before macrotasks like setTimeout callbacks get processed.

Tips

  1. 01Use the native queueMicrotask() method to run scripts immediately after synchronous blocks but before paint updates.
  2. 02Split heavy data processing into smaller setTimeout batches to give browsers time to render frames.

Warnings

  1. 01Running a long synchronous loop blocks the single execution thread, freezing page interactions and rendering updates.
  2. 02Remember that recursive promise microtasks can starve macrotasks by preventing the event loop from advancing.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Event Loop
Chapter 29 · Page 230
Advanced

JavaScript Event Loop

(continued)

The Call Stack

  • Call stack frames

    Tracks function calls in progress, stacking execution frames until returns occur.

    function a() { b(); }
    function b() { console.log("b"); }
    a(); // pushes a, then b, then pops
  • Single execution thread

    Allows only one stack block to run at any single time.

    // Synchronous execution runs sequentially
  • Sync completeness

    Processes synchronous scripts completely before checking background event queues.

    console.log(1);
    console.log(2);
    // 1 always logs before 2
  • Stack overflow

    Triggers errors when unbounded recursive calls consume all stack memory.

    function recurse() { return recurse(); }
    // recurse(); // Maximum stack exceeded
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Event Loop
Chapter 29 · Page 231
Advanced

JavaScript Event Loop

(continued)

Macrotasks and the Task Queue

  • Macrotask callbacks

    Includes timer callbacks, network input, and user action triggers.

    setTimeout(() => console.log("macro"), 0);
    console.log("sync");
  • Single task turns

    Executes exactly one macrotask per event loop rotation iteration.

    setTimeout(() => console.log("1"), 0);
    setTimeout(() => console.log("2"), 0);
    // separate event loop iterations
  • Browser painting

    Interleaves browser paint updates between subsequent task queue turns.

    // Repaints occur after a macrotask completes
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Event Loop
Chapter 29 · Page 232
Advanced

JavaScript Event Loop

(continued)

Microtasks and Promises

  • Promise microtasks

    Runs resolve, reject, and finally callbacks inside the microtask queue.

    Promise.resolve().then(() => console.log("micro"));
  • Direct queueing

    Schedules low-level microtasks directly using the queueMicrotask method.

    queueMicrotask(() => console.log("fast"));
  • Full queue draining

    Forces all queued microtasks to run before the loop advances.

    Promise.resolve().then(() => console.log("m1"));
    Promise.resolve().then(() => console.log("m2"));
    // m1 and m2 execute back-to-back
  • Nested microtasks

    Processes nested microtasks inside the same loop iteration drain phase.

    Promise.resolve().then(() => {
      Promise.resolve().then(() => console.log("nested"));
    });
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Event Loop
Chapter 29 · Page 233
Advanced

JavaScript Event Loop

(continued)

setTimeout vs Promise Ordering

  • Order priority

    Executes promise resolutions before timers scheduled within the same block.

    setTimeout(() => console.log("time"), 0);
    Promise.resolve().then(() => console.log("prom"));
    // logs: prom, time
  • Loop interleaving

    Runs all pending microtasks before processing any scheduled timeout callbacks.

    setTimeout(() => console.log("time"), 0);
    [1, 2].forEach(n => {
      Promise.resolve().then(() => console.log(n));
    });
    // logs: 1, 2, time
  • rAF visual timing

    Runs animation callbacks before paint updates, outside standard queues.

    requestAnimationFrame(() => console.log("paint"));
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Event Loop
Chapter 29 · Page 234
Advanced

JavaScript Event Loop

(continued)

UI Responsiveness

  • Execution chunking

    Schedules iteration batches with setTimeout to avoid locking layout repaints.

    function chunk(items, index = 0) {
      const end = Math.min(index + 100, items.length);
      for (let i = index; i < end; i++) { /* do work */ }
      if (end < items.length) {
        setTimeout(() => chunk(items, end), 0);
      }
    }
  • Web Workers

    Delegates heavy computations to separate threads away from main render loops.

    const worker = new Worker("task.js");
    worker.postMessage(data);
    worker.onmessage = e => console.log(e.data);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Event Loop
Chapter 29 · Page 235
Advanced

JavaScript Event Loop

(FAQ)

FAQ

The event loop orchestrates asynchronous callbacks inside a single-threaded runtime. It polls task queues when the call stack clears and forwards pending operations to the execution thread.

Promises resolve inside the microtask queue, which has higher execution priority. The event loop drains all microtasks before picking up the next macrotask from the timer queue.

Microtasks handle Promise resolutions and direct queueMicrotask() actions. Macrotasks process callbacks from timers, user interactions, and fetch operations. Microtasks drain completely between each individual macrotask.

JavaScript runs on a single main thread. Long calculations occupy the call stack, preventing the event loop from rendering layout repaints or handling clicks. Offload heavy math to Web Workers.

No, a zero delay registers a callback into the macrotask queue. The engine must finish executing the current call stack and empty the microtask queue before starting it.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Event Loop
Chapter 29 · Page 236
Advanced

JavaScript Event Loop

(In Practice)
In Practice

Predicting Execution Order

Combines synchronous execution, Promise microtasks, a setTimeout timer, and async awaits to demonstrate execution priorities.

  1. 01Execute the synchronous start log statement immediately.
  2. 02Register a zero-delay timeout callback into the macrotask queue.
  3. 03Push a Promise resolution callback to the microtask queue.
  4. 04Run the async function synchronously up to the first await keyword.
  5. 05Drain the complete microtask queue before picking up the pending macrotask.
console.log("1: sync start");

setTimeout(() => {
  console.log("2: setTimeout (macrotask)");
}, 0);

Promise.resolve().then(() => {
  console.log("3: promise (microtask)");
});

async function run() {
  console.log("4: async start (sync)");
  await null;
  console.log("5: async microtask");
}
run();

console.log("6: sync end");

// Output order: 1, 4, 6, 3, 5, 2
Takeaway

Synchronous execution completes first, then the microtask queue drains fully, and finally the next macrotask runs.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Generators
Chapter 30 · Page 237
Advanced

JavaScript Generators

Learn how generator functions pause and resume execution to build lazy sequences and iterables.

TL;DR

  1. 01Declare generators with function* to suspend and resume functions.
  2. 02Emit values lazily on demand using the yield keyword.
  3. 03Forward iteration sequences to external collections using yield* delegation.

Tips

  1. 01Use generators to compute massive data sequences lazily without consuming system memory up front.
  2. 02Assign generator methods to Symbol.iterator properties to create custom iterables cleanly.

Warnings

  1. 01Catch exceptions thrown inside generator scopes to prevent them from closing the iterator permanently.
  2. 02Avoid using spread syntax on infinite generators to prevent crashing the browser thread.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Generators
Chapter 30 · Page 238
Advanced

JavaScript Generators

(continued)

Generator Basics

  • function* declaration

    Declares generators which return an iterator object instead of running code.

    function* counter() {
      yield 1;
      yield 2;
    }
    const it = counter();
  • next() calls

    Resumes execution block internally until encountering the next yield line.

    it.next(); // { value: 1, done: false }
    it.next(); // { value: 2, done: false }
  • Return values

    Signals completion with done true and returns standard values if declared.

    function* range() {
      yield 1;
      return "stop";
    }
    const it2 = range();
    it2.next(); // { value: 1, done: false }
    it2.next(); // { value: "stop", done: true }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Generators
Chapter 30 · Page 239
Advanced

JavaScript Generators

(continued)

Controlling Generators

  • Value injection

    Passes parameter values back into the generator at pause lines.

    function* greet() {
      const name = yield "name?";
      yield `Hi, ${name}`;
    }
    const g = greet();
    g.next(); // "name?"
    g.next("Ada"); // { value: "Hi, Ada", done: false }
  • return() method

    Terminates generator runs early, returning specified values immediately.

    const it = counter();
    it.next();
    it.return("end"); // { value: "end", done: true }
  • throw() method

    Injects exceptions directly into generators at the current yield line.

    function* safe() {
      try { yield 1; } catch (e) { yield e.message; }
    }
    const it = safe();
    it.next();
    it.throw(new Error("oops")); // value: "oops"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Generators
Chapter 30 · Page 240
Advanced

JavaScript Generators

(continued)

Lazy Sequences

  • Infinite generators

    Computes unending data streams on demand with zero memory leaks.

    function* naturals() {
      let n = 1;
      while (true) yield n++;
    }
    const it = naturals();
    it.next().value; // 1
  • take() boundaries

    Extracts limited arrays from lazy sequences using break counters.

    function take(iterable, count) {
      const res = [];
      for (const v of iterable) {
        if (res.length >= count) break;
        res.push(v);
      }
      return res;
    }
    take(naturals(), 3); // [1, 2, 3]
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Generators
Chapter 30 · Page 241
Advanced

JavaScript Generators

(continued)

Custom Iterables

  • Symbol.iterator method

    Attaches generators to class object structures to allow for-of loops.

    class Range {
      constructor(start, end) {
        this.start = start;
        this.end = end;
      }
      *[Symbol.iterator]() {
        for (let i = this.start; i <= this.end; i++) {
          yield i;
        }
      }
    }
    [...new Range(1, 3)]; // [1, 2, 3]
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Generators
Chapter 30 · Page 242
Advanced

JavaScript Generators

(continued)

Delegation with yield*

  • Iterable forwarding

    Delegates execution directly to another iterable structure, avoiding loops.

    function* combine() {
      yield* [1, 2];
      yield* "ab";
    }
    [...combine()]; // [1, 2, "a", "b"]
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Generators
Chapter 30 · Page 243
Advanced

JavaScript Generators

(FAQ)

FAQ

Regular functions run to completion immediately when invoked. Generator functions, declared with function*, return an iterator instead. The function body runs only when calling .next().

The yield keyword pauses generator function execution and outputs a value to the caller. The generator remains frozen until the caller invokes .next() again.

Use yield* to forward values from another iterable, like an array or generator. This avoids manual loops and passes .next(), .return(), and .throw() down automatically.

The .return(value) method closes the generator early, returning the value. The .throw(error) method injects an exception at the current pause point, letting try/catch handle it.

Yes, they are. Assign a generator function to the object's Symbol.iterator property. The engine handles iterator tracking and value formats automatically under the hood.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Generators
Chapter 30 · Page 244
Advanced

JavaScript Generators

(In Practice)
In Practice

Lazy Fibonacci Sequence Generator

Generates an infinite Fibonacci sequence lazily using destructuring assignment and a custom take controller.

  1. 01Initialize variables to store the two initial sequence values.
  2. 02Establish an infinite loop that yields numbers on demand.
  3. 03Yield the current sequence value back to the caller.
  4. 04Calculate the subsequent numbers using destructuring array assignments.
  5. 05Pull a subset array of values without triggering infinite processing.
function* fibonacci() {
  let [prev, curr] = [0, 1];
  while (true) {
    yield curr;
    [prev, curr] = [curr, prev + curr];
  }
}

function take(generator, count) {
  const result = [];
  for (const value of generator) {
    if (result.length >= count) break;
    result.push(value);
  }
  return result;
}

console.log(take(fibonacci(), 5)); // [1, 1, 2, 3, 5]
Takeaway

Generators allow processing infinite data sequences safely by computing next values only when requested.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Iterators
Chapter 31 · Page 245
Advanced

JavaScript Iterators

Learn iterators, the iteration protocol, and generators for controlling how data is consumed.

TL;DR

  1. 01Expose a next method returning value and done properties.
  2. 02Implement Symbol.iterator to make custom objects natively iterable.
  3. 03Use generator functions to construct custom iterables efficiently.

Tips

  1. 01Use generator functions to implement the iteration contract automatically without manual state tracking.
  2. 02Delegate execution to nested iterables using yield* to simplify generator loop declarations.

Warnings

  1. 01Remember that exhausted iterators cannot be reused without obtaining a fresh iterator instance.
  2. 02Convert plain objects using Object.entries() before attempting loop iteration over them.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Iterators
Chapter 31 · Page 246
Advanced

JavaScript Iterators

(continued)

What Iterators Are

  • Iterator definition

    Provides a next method returning value and done flags.

    const arr = [10, 20];
    const it = arr[Symbol.iterator]();
    it.next(); // { value: 10, done: false }
  • Iteration state

    Tracks progress dynamically, returning done: true when complete.

    it.next(); // { value: 20, done: false }
    it.next(); // { value: undefined, done: true }
  • Underlying support

    Powers loops, spreads, and destructuring operations implicitly.

    const [x, y] = [10, 20]; // uses iterator
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Iterators
Chapter 31 · Page 247
Advanced

JavaScript Iterators

(continued)

Iteration Protocol

  • Custom iterables

    Implements Symbol.iterator to make objects work with for-of.

    const obj = {
      data: [1, 2, 3],
      [Symbol.iterator]() {
        let i = 0;
        return {
          next: () => ({
            value: this.data[i],
            done: i++ >= this.data.length
          })
        };
      }
    };
    for (const n of obj) console.log(n);
  • Required structures

    Demands the standard iterator method shape to match engine interfaces.

    // Iterator returns: { next() { ... } }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Iterators
Chapter 31 · Page 248
Advanced

JavaScript Iterators

(continued)

Built-in Iterables

  • Standard collections

    Provides native iteration for strings, arrays, sets, and maps.

    for (const char of "Hi!") console.log(char);
    for (const val of new Set([1, 2])) console.log(val);
  • Map entries

    Iterates over key-value pairs using array destructuring syntax.

    const map = new Map([['a', 1]]);
    for (const [k, v] of map) console.log(k, v);
  • DOM NodeLists

    Supports for-of iteration on elements retrieved from DOM queries.

    const divs = document.querySelectorAll("div");
    for (const div of divs) console.log(div);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Iterators
Chapter 31 · Page 249
Advanced

JavaScript Iterators

(continued)

Generators

  • Generator functions

    Pauses function execution using the yield keyword.

    function* greet() {
      const name = yield "name?";
      yield `Hello, ${name}!`;
    }
    const g = greet();
    g.next().value; // "name?"
    g.next("Ada").value; // "Hello, Ada!"
  • Generator delegation

    Delegates execution to nested iterables using the yield* operator.

    function* combine() {
      yield* [1, 2];
      yield* ['a', 'b'];
    }
    console.log([...combine()]); // [1, 2, 'a', 'b']
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Iterators
Chapter 31 · Page 250
Advanced

JavaScript Iterators

(FAQ)

FAQ

An iterable is an object defining a Symbol.iterator method. An iterator is the returned object containing a next() method. Arrays are iterables, while array.values() returns an iterator.

Yes, define a Symbol.iterator method returning a next() method on your object. That method must return a {value, done} structure. The object then supports for...of loops.

Iterators hold internal state and become exhausted when they return done: true. Calling next() afterward continues returning true. Retrieve a fresh iterator to loop again.

Use generator functions for complex state tracking. The runtime automatically manages state boundaries and suspends executions. Manual iterators are better for highly specific performance scenarios.

Yes, both operations rely on the standard Symbol.iterator protocol. Any object implementing this protocol will work correctly with destructuring and spread operators.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Iterators
Chapter 31 · Page 251
Advanced

JavaScript Iterators

(In Practice)
In Practice

Paginated API Response Iterator

Wraps a paginated server endpoint inside a custom async iterator for streaming record sets.

  1. 01Set up local trackers for page counts and finished statuses.
  2. 02Expose the iterator protocol handler method on the container.
  3. 03Define the async next method structure to request records.
  4. 04Fetch server data records and adjust page markers recursively.
  5. 05Return the received records list or done flags.
function createPageIterator(fetcher) {
  let nextPage = 1;
  let isDone = false;

  return {
    [Symbol.iterator]() {
      return {
        async next() {
          if (isDone) {
            return { done: true };
          }
          const res = await fetcher(nextPage);
          if (res.hasMore) {
            nextPage++;
          } else {
            isDone = true;
          }
          return { value: res.items, done: false };
        }
      };
    }
  };
}
Takeaway

Custom iteration protocols allow you to stream paginated datasets as if they were simple local loops.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Prototypal Inheritance
Chapter 32 · Page 252
Advanced

JavaScript Prototypal Inheritance

Understand the prototype chain, Object.create, and how class syntax wraps prototypal inheritance.

TL;DR

  1. 01Inherit object properties dynamically through a linked chain of prototypes.
  2. 02Construct prototype linkages directly using the standard Object.create method.
  3. 03Use modern class declarations as syntactic sugar over prototype chains.

Tips

  1. 01Use the standard Object.getPrototypeOf() method instead of legacy properties like __proto__ to inspect prototypes.
  2. 02Verify own object properties explicitly using Object.hasOwn() before accessing inherited properties.

Warnings

  1. 01Avoid setting object prototypes dynamically using Object.setPrototypeOf because it degrades property access performance.
  2. 02Filter properties inside for...in loops to prevent iteration leaks from inherited enumerable method names.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Prototypal Inheritance
Chapter 32 · Page 253
Advanced

JavaScript Prototypal Inheritance

(continued)

The Prototype Chain

  • Prototype linkage

    Links objects together in a prototype chain for sharing property values.

    const animal = { eats: true };
    const rabbit = Object.create(animal);
    rabbit.hops = true;
    console.log(rabbit.eats); // true
  • Chain lookup rules

    Walks up prototype chains until matching properties are found.

    // Lookup: rabbit -> animal -> Object.prototype
  • Chain end

    Ends prototype search trees at Object.prototype, which has null prototype.

    const proto = Object.getPrototypeOf(
      Object.prototype
    );
    console.log(proto); // null
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Prototypal Inheritance
Chapter 32 · Page 254
Advanced

JavaScript Prototypal Inheritance

(continued)

Creating Prototypes

  • Object.create

    Creates new object instances with explicit prototype mappings.

    const base = { greet() { return "hi"; } };
    const obj = Object.create(base);
    console.log(obj.greet()); // "hi"
  • Inspecting prototypes

    Inspects prototype references using getPrototypeOf cleanly.

    Object.getPrototypeOf(obj) === base; // true
  • Inheritance without classes

    Models inheritance associations directly without requiring constructors.

    const parent = { val: 42 };
    const child = Object.create(parent);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Prototypal Inheritance
Chapter 32 · Page 255
Advanced

JavaScript Prototypal Inheritance

(continued)

Constructor prototype

  • Constructor functions

    Attaches shared functions directly to constructor prototype properties.

    function Dog(name) { this.name = name; }
    Dog.prototype.bark = function() {
      return `${this.name} barks`;
    };
    const rex = new Dog("Rex");
  • Memory optimization

    Shares method references across all constructed instances.

    // rex.bark links to Dog.prototype.bark
  • instanceof verification

    Confirms prototype links exist in target instance chains.

    console.log(rex instanceof Dog); // true
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Prototypal Inheritance
Chapter 32 · Page 256
Advanced

JavaScript Prototypal Inheritance

(continued)

Class Sugar

  • class keyword

    Compiles class helper blocks to standard prototypes.

    class Dog {
      constructor(name) { this.name = name; }
      bark() { return `${this.name} barks`; }
    }
    typeof Dog; // "function"
  • Subclass extends

    Sets up prototype chains between parent and child automatically.

    class Puppy extends Dog {
      bark() { return super.bark() + "!"; }
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Prototypal Inheritance
Chapter 32 · Page 257
Advanced

JavaScript Prototypal Inheritance

(continued)

Property Shadowing

  • hasOwn check

    Checks property existence directly on the local object instance.

    const base = { color: "red" };
    const item = Object.create(base);
    console.log(Object.hasOwn(item, "color")); // false
  • Property overrides

    Shadows prototype property definitions by setting local values.

    item.color = "blue";
    console.log(item.color); // "blue"
    console.log(base.color); // "red"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Prototypal Inheritance
Chapter 32 · Page 258
Advanced

JavaScript Prototypal Inheritance

(FAQ)

FAQ

Every JavaScript object holds an internal link pointing to a prototype object. Property lookups walk up this chain recursively until they locate a matching property or reach null.

The __proto__ property is a deprecated legacy accessor. The Object.getPrototypeOf() method is the modern, standardized interface. You should use the functional methods in production code.

No, it is not. The class keyword compiles to a standard constructor function. Methods declared in classes sit directly on the constructor's prototype object at runtime.

Shadowing occurs when an object defines a property matching the name of a prototype property. The object's own property overrides the lookup value without altering the prototype itself.

Use the Object.hasOwn(obj, prop) method. This returns true if the property exists directly on the target instance. It returns false for inherited prototype properties.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Prototypal Inheritance
Chapter 32 · Page 259
Advanced

JavaScript Prototypal Inheritance

(In Practice)
In Practice

Compiling Class Inheritance to Prototypes

Demonstrates how modern ES6 classes are transformed into prototype constructors under the hood.

  1. 01Create a base constructor function to assign user properties.
  2. 02Attach the login method to the user constructor prototype.
  3. 03Create a subclass admin constructor calling the parent constructor context.
  4. 04Bind the admin prototype to a new object inheriting from the user prototype.
  5. 05Reset the admin constructor reference to point to itself correctly.
function createCompilledClass() {
  function User(name) {
    this.name = name;
  }

  User.prototype.login = function() {
    return this.name + " logged in";
  };

  function Admin(name, role) {
    User.call(this, name);
    this.role = role;
  }

  Admin.prototype = Object.create(
    User.prototype
  );
  Admin.prototype.constructor = Admin;

  return { User, Admin };
}
Takeaway

Class declarations compile to constructor functions with shared methods placed on their prototype chains.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Proxy and Reflect
Chapter 33 · Page 260
Advanced

JavaScript Proxy and Reflect

Learn how Proxy traps and the Reflect API intercept and control object behavior in JavaScript.

TL;DR

  1. 01Wrap target objects with Proxy wrappers to intercept standard operations.
  2. 02Define handler traps like get and set to customize behaviors.
  3. 03Use the Reflect API to forward default actions inside traps.

Tips

  1. 01Invoke matching Reflect methods inside every proxy trap to preserve default language behavior for properties.
  2. 02Create validation layers using a proxy set trap to reject invalid assignments before updating targets.

Warnings

  1. 01Always pass the receiver argument to Reflect.get to keep getters bound to the correct context.
  2. 02Avoid wrapping objects in performance-critical loops because proxy traps introduce function invocation overhead.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Proxy and Reflect
Chapter 33 · Page 261
Advanced

JavaScript Proxy and Reflect

(continued)

Creating a Proxy

  • Proxy wrapper

    Wraps target objects using the Proxy constructor with custom handlers.

    const target = { name: "Ada" };
    const proxy = new Proxy(target, {});
    console.log(proxy.name); // "Ada"
  • Handler traps

    Specifies trap functions in handlers to intercept object reads.

    const handler = {
      get(target, prop) {
        return target[prop];
      }
    };
    const proxy = new Proxy({ x: 1 }, handler);
  • Function proxying

    Wraps executable function objects to intercept call parameters.

    function greet(name) { return `Hi ${name}`; }
    const pr = new Proxy(greet, {
      apply(t, thisArg, args) {
        return t(...args);
      }
    });
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Proxy and Reflect
Chapter 33 · Page 262
Advanced

JavaScript Proxy and Reflect

(continued)

Common Traps

  • get trap

    Intercepts property access lookups and method executions.

    const p = new Proxy({ a: 1 }, {
      get(target, prop) {
        return prop in target ? target[prop] : "missing";
      }
    });
  • set trap

    Intercepts property assignments and returns confirmation flags.

    const p = new Proxy({}, {
      set(target, prop, value) {
        target[prop] = value;
        return true;
      }
    });
  • has trap

    Intercepts the boolean property presence verification check.

    const p = new Proxy({ secret: 1 }, {
      has(target, prop) {
        return prop === "secret" ? false : prop in target;
      }
    });
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Proxy and Reflect
Chapter 33 · Page 263
Advanced

JavaScript Proxy and Reflect

(continued)

Reflect Default Behavior

  • Reflect forwarding

    Invokes default target operations inside custom proxy traps.

    const p = new Proxy({ a: 1 }, {
      get(target, prop, receiver) {
        return Reflect.get(target, prop, receiver);
      }
    });
  • Context preservation

    Passes receivers to Reflect to maintain correct property accessor bindings.

    const target = {
      _v: 10,
      get v() { return this._v; }
    };
  • Execution return flags

    Exposes execution success values as standard true or false flags.

    const obj = Object.freeze({ a: 1 });
    const ok = Reflect.set(obj, "a", 2); // false
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Proxy and Reflect
Chapter 33 · Page 264
Advanced

JavaScript Proxy and Reflect

(continued)

Practical Use Cases

  • Input validation

    Enforces variable type constraints prior to committing assignments.

    const validator = {
      set(target, prop, value) {
        if (typeof value !== "number") return false;
        return Reflect.set(target, prop, value);
      }
    };
  • Default attributes

    Supplies default values when missing property keys are queried.

    const fallback = {
      get(target, prop) {
        return prop in target ? target[prop] : 0;
      }
    };
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Proxy and Reflect
Chapter 33 · Page 265
Advanced

JavaScript Proxy and Reflect

(continued)

Common Pitfalls

  • Losing this context

    Avoids method execution failure by forwarding matching receivers.

    // Always pass 'receiver' to Reflect.get()
  • Identity checks

    Checks references carefully since proxies do not equal target references.

    const target = {};
    const proxy = new Proxy(target, {});
    console.log(proxy === target); // false
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Proxy and Reflect
Chapter 33 · Page 266
Advanced

JavaScript Proxy and Reflect

(FAQ)

FAQ

A Proxy wraps target objects to intercept core operations like property reads. You specify custom logic via handler functions called traps. This is useful for validation, logging, and reactivity.

A Proxy intercepts actions on objects. The Reflect API provides matching methods to execute standard behaviors. You call Reflect methods inside traps to forward requests.

Using Reflect methods correctly preserves the this binding context for get accessors. It also returns consistent booleans indicating success, avoiding silent failures in non-strict modes.

The get and set traps intercept property accesses. The has trap handles the in operator. The apply trap intercepts function executions when targets are callable.

Yes, because every trapped interaction calls a handler function. This overhead is fine for configuration boundaries or schemas. Avoid using proxies in tight, performance-critical loops.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Proxy and Reflect
Chapter 33 · Page 267
Advanced

JavaScript Proxy and Reflect

(In Practice)
In Practice

Validation Proxy Schema

Wraps an object in a validation proxy to enforce strict data types on property assignments.

  1. 01Define a strict type validation rules checklist schema.
  2. 02Instantiate a new Proxy with a custom set trap handler.
  3. 03Intercept property assignment requests at the set boundary.
  4. 04Verify that incoming values match the validated schema types.
  5. 05Apply validated assignments using Reflect set calls.
function createValidatedUser() {
  const schema = {
    age: "number",
    name: "string"
  };

  return new Proxy({}, {
    set(target, prop, value) {
      if (prop in schema) {
        if (typeof value !== schema[prop]) {
          throw new TypeError(
            prop + " must be a " + schema[prop]
          );
        }
      }
      return Reflect.set(target, prop, value);
    }
  });
}
Takeaway

Set traps validate data before assignments commit, protecting target instances from runtime configuration bugs.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Regular Expressions
Chapter 34 · Page 268
Advanced

JavaScript Regular Expressions

Learn regex patterns, flags, exec, test, match, and replace for powerful string processing.

TL;DR

  1. 01Define literal patterns with slashes or construct them using variables.
  2. 02Verify expressions with test and extract groups using matchAll.
  3. 03Replace target strings dynamically by passing matching replacement patterns.

Tips

  1. 01Use named capture groups to make complex regular expressions much easier to read and maintain.
  2. 02Create fresh regex instances or reset lastIndex to zero when executing global state matches.

Warnings

  1. 01Remember that global regular expressions maintain state between execution runs via the lastIndex property.
  2. 02Escape user-provided variables with backslashes before constructing dynamic patterns to prevent parsing failures.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Regular Expressions
Chapter 34 · Page 269
Advanced

JavaScript Regular Expressions

(continued)

Creating Patterns

  • Regex literal

    Defines static patterns using forward slash brackets.

    const pattern = /hello/;
    console.log(pattern.test("hello world")); // true
  • RegExp constructor

    Compiles patterns dynamically at runtime from string variables.

    const word = "hello";
    const pattern = new RegExp(word);
    console.log(pattern.test("say hello")); // true
  • Character classes

    Matches specific characters from defined character sets.

    /[aeiou]/.test("hello");  // true
    /[0-9]/.test("abc123"); // true
  • String anchors

    Enforces starting and ending boundaries on checks.

    /^hello/.test("hello world"); // true
    /world$/.test("hello world"); // true
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Regular Expressions
Chapter 34 · Page 270
Advanced

JavaScript Regular Expressions

(continued)

Quantifiers

  • Zero or more

    Matches zero or more occurrences using the asterisk operator.

    /a*b/.test("b");    // true
    /a*b/.test("aaab"); // true
  • One or more

    Matches one or more occurrences using the plus operator.

    /a+b/.test("ab"); // true
    /a+b/.test("b");  // false
  • Optional quantifier

    Marks elements as optional using the question mark operator.

    /colou?r/.test("color");  // true
    /colou?r/.test("colour"); // true
  • Lazy matching

    Appends ? to quantifiers to match minimal characters.

    const greedy = "<a><b>".match(/<.+>/)[0];  // "<a><b>"
    const lazy = "<a><b>".match(/<.+?>/)[0]; // "<a>"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Regular Expressions
Chapter 34 · Page 271
Advanced

JavaScript Regular Expressions

(continued)

Flags and Methods

  • Regex flags

    Specifies search parameters like case-insensitivity or global parsing.

    /hello/i.test("HELLO"); // true
    "hi hi".match(/hi/g); // ["hi", "hi"]
  • exec() details

    Returns match arrays along with capture groups.

    const res = /(\w+)@(\w+)/.exec("user@test.com");
    // res[1] === "user", res[2] === "test"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Regular Expressions
Chapter 34 · Page 272
Advanced

JavaScript Regular Expressions

(continued)

Replacing and Testing

  • String replace

    Replaces search results with new replacement string values.

    "hello world".replace(/hello/, "hi"); // "hi world"
  • String replaceAll

    Replaces all matching entries globally when using g flag expressions.

    "hi hi".replaceAll(/hi/g, "hello"); // "hello hello"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Regular Expressions
Chapter 34 · Page 273
Advanced

JavaScript Regular Expressions

(continued)

Common Regex Patterns

  • Validation samples

    Validates formats like phone numbers or simple emails.

    /^\d{3}-\d{3}-\d{4}$/.test("123-456-7890"); // true
  • Whitespace collapse

    Collapses duplicate spaces and trims outer edges.

    const clean = " a  b ".replace(/\s+/g, " ").trim();
    // clean === "a b"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Regular Expressions
Chapter 34 · Page 274
Advanced

JavaScript Regular Expressions

(FAQ)

FAQ

Use the RegExp constructor when compiling patterns dynamically from variables. Use literal patterns for static definitions. Literals compile during script loading and catch syntax bugs early.

Greedy quantifiers match as many characters as possible. Lazy quantifiers append a question mark to match as few as possible. For example, .*? performs lazy matches.

Use String.prototype.matchAll() with the g flag. This returns an iterator containing complete match details and capture groups. Regular match() drops capture group indices.

The replace() method defaults to updating only the first match without a global g flag. Use replaceAll() or include the global flag to substitute all instances.

Parentheses wrap sections of patterns to create capture groups. Retrieve them using index offsets like match[1]. Alternatively, use (?<name>) syntax to query named capture groups.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Regular Expressions
Chapter 34 · Page 275
Advanced

JavaScript Regular Expressions

(In Practice)
In Practice

Parsing URL Strings with Named Groups

Parses database or web addresses using regular expression named capture groups to extract protocol and host names.

  1. 01Write a validation regular expression pattern specifying named capture groups.
  2. 02Execute the pattern against the target string address parameters.
  3. 03Confirm that a valid match details response was retrieved.
  4. 04Extract captured keys from the matched groups property index.
  5. 05Return the structured details object back to callers.
function parseConnection(str) {
  const regex =
    /^(?<proto>https?):\/\/(?<host>[^/]+)$/;

  const match = regex.exec(str);
  if (!match) return null;

  const { proto, host } = match.groups;
  return { proto, host };
}
Takeaway

Named capture groups document intent directly in patterns, making parsed string details easy to query.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Symbols
Chapter 35 · Page 276
Advanced

JavaScript Symbols

Use unique Symbol values as collision-free object keys and customize built-in object behavior.

TL;DR

  1. 01Instantiate unique primitive values with the built-in Symbol factory.
  2. 02Configure unique collision-free keys hidden from standard object loop enumerations.
  3. 03Use well-known symbols to customize core language behaviors like iteration.

Tips

  1. 01Use local symbols to declare properties that will never collide with third-party keys.
  2. 02Retrieve shared symbol values across realms using the global Symbol.for() registry.

Warnings

  1. 01Avoid calling Symbol using new because symbols are primitives rather than constructible classes.
  2. 02Remember that symbol properties are omitted by standard operations like JSON.stringify and loops.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Symbols
Chapter 35 · Page 277
Advanced

JavaScript Symbols

(continued)

What Symbols Are

  • Unique primitive

    Generates unique primitive values on every function call.

    const a = Symbol("id");
    const b = Symbol("id");
    console.log(a === b); // false
  • Description debugging

    Assigns debugging descriptions which do not affect symbol identity.

    const s = Symbol("label");
    console.log(s.description); // "label"
  • Primitives type

    Returns symbol from typeof checks.

    console.log(typeof Symbol()); // "symbol"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Symbols
Chapter 35 · Page 278
Advanced

JavaScript Symbols

(continued)

Object Keys

  • Symbol properties

    Assigns properties using symbol keys to guarantee collision-free attributes.

    const KEY = Symbol("key");
    const user = { name: "Ada", [KEY]: 42 };
  • Bracket accesses

    Queries symbol keys using bracket notation rather than dot accesses.

    console.log(user[KEY]); // 42
  • Descriptors listing

    Lists symbol keys using Reflect methods.

    Reflect.ownKeys(user); // ["name", Symbol(key)]
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Symbols
Chapter 35 · Page 279
Advanced

JavaScript Symbols

(continued)

Omitted Enumeration

  • Loop exclusion

    Excludes symbol properties from keys listings and loops.

    const obj = { name: "A", [Symbol("id")]: 1 };
    console.log(Object.keys(obj)); // ["name"]
  • JSON serialization

    Omits symbol keys during stringify operations.

    console.log(JSON.stringify(obj)); // '{"name":"A"}'
  • Explicit queries

    Queries symbols using specialized getOwnPropertySymbols calls.

    Object.getOwnPropertySymbols(obj); // [Symbol(id)]
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Symbols
Chapter 35 · Page 280
Advanced

JavaScript Symbols

(continued)

Well-Known Symbols

  • Symbol.iterator

    Enables custom iteration behavior on plain objects.

    const range = {
      [Symbol.iterator]() {
        return { next: () => ({ done: true }) };
      }
    };
    [...range];
  • Symbol.toPrimitive

    Enforces custom conversions into primitives.

    const cash = {
      amount: 50,
      [Symbol.toPrimitive](hint) {
        return hint === "string" ? `$${this.amount}` : this.amount;
      }
    };
  • Symbol.hasInstance

    Overrides instanceof check mechanics for target configurations.

    class Even {
      static [Symbol.hasInstance](num) {
        return num % 2 === 0;
      }
    }
    console.log(4 instanceof Even); // true
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Symbols
Chapter 35 · Page 281
Advanced

JavaScript Symbols

(continued)

Global Registry

  • Symbol.for

    Registers shared symbol instances in a global scope index.

    const a = Symbol.for("app.id");
    const b = Symbol.for("app.id");
    console.log(a === b); // true
  • Symbol.keyFor

    Returns registered index strings matching active shared symbols.

    console.log(Symbol.keyFor(a)); // "app.id"
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript Symbols
Chapter 35 · Page 282
Advanced

JavaScript Symbols

(FAQ)

FAQ

A Symbol represents a unique primitive value that avoids key collisions. It allows adding custom properties to objects safely. Well-known symbols hook directly into core operations.

By design, serialization routines like JSON.stringify only process string-keyed properties. This restriction lets symbols act as hidden metadata boundaries. They remain safe from accidental log outputs.

The Symbol() factory guarantees unique instances per call. The Symbol.for() method queries the global symbol registry first. It retrieves matching instances if they already exist.

Well-known symbols are built-in hooks like Symbol.iterator. They enable objects to customize default language behaviors. This includes customizing string casting and enabling iteration protocols.

No, they are not. The Object.getOwnPropertySymbols() method returns all symbol keys from target instances. Anyone holding reference handles can access the property values.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript Symbols
Chapter 35 · Page 283
Advanced

JavaScript Symbols

(In Practice)
In Practice

Private Metadata Attachment

Uses local Symbols to attach internal metadata to objects safely, preventing collision with user properties.

  1. 01Instantiate a local Symbol identifier to act as the metadata key.
  2. 02Define a setMetadata function mapping data to the object symbol key.
  3. 03Assign metadata to the object using bracket notation entries.
  4. 04Define a getMetadata function to retrieve values using the key.
  5. 05Return the helper functions while keeping the Symbol hidden.
function createMetadataSystem() {
  const METADATA = Symbol("internal_metadata");

  function setMetadata(obj, data) {
    obj[METADATA] = data;
  }

  function getMetadata(obj) {
    return obj[METADATA];
  }

  return { setMetadata, getMetadata };
}
Takeaway

Symbol properties guarantee collision-free attributes, which makes them ideal for attaching internal metadata safely.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript WeakMap and WeakRef
Chapter 36 · Page 284
Advanced

JavaScript WeakMap and WeakRef

Store object-keyed data and hold references without blocking garbage collection in JavaScript.

TL;DR

  1. 01Store object-keyed properties using weak references to support garbage collection.
  2. 02Hold object references without preventing the engine garbage collection process.
  3. 03Use FinalizationRegistry objects to configure cleanup callbacks for collected references.

Tips

  1. 01Attach metadata records to external object keys safely using self-cleaning WeakMap caches.
  2. 02Create memory-sensitive caches using WeakRef to let engines collect references under pressure.

Warnings

  1. 01Avoid setting primitive keys on WeakMap because keys must always be object references.
  2. 02Do not rely on FinalizationRegistry for critical updates since callback execution timing is unpredictable.
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript WeakMap and WeakRef
Chapter 36 · Page 285
Advanced

JavaScript WeakMap and WeakRef

(continued)

What WeakMap Is

  • WeakMap key values

    Stores key-value entries where keys are object references.

    const cache = new WeakMap();
    const user = { id: 1 };
    cache.set(user, { clicks: 3 });
  • Weak references

    Allows garbage collection of key objects when references disappear.

    let el = document.querySelector("#widget");
    cache.set(el, { clicks: 0 });
    el = null; // entry can be collected now
  • Key constraints

    Requires object keys, throwing errors when primitives are passed.

    // cache.set("key", 1); // TypeError
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript WeakMap and WeakRef
Chapter 36 · Page 286
Advanced

JavaScript WeakMap and WeakRef

(continued)

Non-Enumerable design

  • No iteration

    Prohibits access to size, keys, and values properties.

    const wm = new WeakMap();
    console.log(wm.size); // undefined
    // [...wm]; // TypeError: wm is not iterable
  • Deterministic safety

    Hides garbage collector actions to keep behavior predictable.

    // Non-enumerable design prevents observation
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript WeakMap and WeakRef
Chapter 36 · Page 287
Advanced

JavaScript WeakMap and WeakRef

(continued)

Private Data Caches

  • Property encapsulation

    Attaches private attributes to objects without changing structures.

    const privateData = new WeakMap();
    class Account {
      constructor(b) { privateData.set(this, { b }); }
      getBal() { return privateData.get(this).b; }
    }
  • Metadata attachment

    Caches calculated values keyed to specific element instances.

    const sizeCache = new WeakMap();
    function getBounding(el) {
      if (!sizeCache.has(el)) {
        sizeCache.set(el, el.getBoundingClientRect());
      }
      return sizeCache.get(el);
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript WeakMap and WeakRef
Chapter 36 · Page 288
Advanced

JavaScript WeakMap and WeakRef

(continued)

WeakRef

  • Object wrappers

    Wraps object references without blocking garbage collection.

    let obj = { data: "large" };
    const ref = new WeakRef(obj);
    ref.deref(); // { data: "large" }
  • deref() checks

    Queries deref references, verifying presence before accesses.

    obj = null;
    // after GC executes:
    const target = ref.deref();
    if (target) console.log(target.data);
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript WeakMap and WeakRef
Chapter 36 · Page 289
Advanced

JavaScript WeakMap and WeakRef

(continued)

FinalizationRegistry

  • Cleanup callbacks

    Registers callbacks to execute after objects are collected.

    const reg = new FinalizationRegistry(held => {
      console.log("collected:", held);
    });
    reg.register(obj, "label");
Notes
Useful Cheatsheetsusefulcheatsheets.com
JavaScript WeakMap and WeakRef
Chapter 36 · Page 290
Advanced

JavaScript WeakMap and WeakRef

(FAQ)

FAQ

Map objects retain strong references to their keys, preventing garbage collection. WeakMap objects hold weak references, allowing keys to be collected. Keys must be objects, and iteration is prohibited.

Garbage collection timing is non-deterministic. Exposing entry lists would reveal when memory recovery occurred. The specification prohibits size and iteration properties to prevent engine leakage.

A WeakRef holds object references without preventing garbage collection. Call .deref() to retrieve targets. This method returns undefined if the object has already been garbage collected.

Use private fields for instance attributes on classes you write. Reach for WeakMap to store private data on foreign instances or plain objects that do not support private fields.

No, engines may skip callbacks if programs exit early. Treat these execution routines as non-critical optimizations. Always use explicit cleanups or try/finally blocks for essential operations.

Useful Cheatsheetsusefulcheatsheets.com
JavaScript WeakMap and WeakRef
Chapter 36 · Page 291
Advanced

JavaScript WeakMap and WeakRef

(In Practice)
In Practice

DOM Element Bounding Rect Cache

Caches DOM bounding rectangles using a WeakMap to automatically purge cache data when nodes are removed.

  1. 01Create a WeakMap instance to hold the DOM element cache.
  2. 02Check if the cache contains bounding rects for the query element.
  3. 03Calculate bounds using the element's bounding rect API.
  4. 04Store calculated bounds in the cache mapped to the element.
  5. 05Return cached bounds directly without executing repetitive calculations.
function createBoundingCache() {
  const cache = new WeakMap();

  function getBounds(element) {
    if (!cache.has(element)) {
      const rect =
        element.getBoundingClientRect();
      cache.set(element, rect);
    }
    return cache.get(element);
  }

  return { getBounds };
}
Takeaway

WeakMap structures automatically clean up cached entries once mapped element nodes are deleted from the DOM.

Preview: The JavaScript Cheatsheet Collection