JavaScript

Variables, functions, arrays and objects, async and promises, the DOM, classes and modules — with a live playground for the array methods that click faster than they read.

Every JavaScript keyword at a glance

Every entry, one line each. Highlighted ones have a detailed example below — click to jump there.

All 161 entries
let
Declares a block-scoped, reassignable variable
const
Declares a block-scoped variable that cannot be reassigned
var
Declares a function-scoped variable, hoisted to the top
typeof
Returns a string naming the type of a value
instanceof
Tests whether an object descends from a constructor
Template literals
Backtick strings that embed expressions with ${}
Destructuring
Unpacks array/object values into distinct variables
Spread (...)
Expands an iterable into individual elements
Rest parameters
Gathers remaining arguments into a real array
Ternary (?:)
condition ? valueIfTrue : valueIfFalse, inline
Nullish coalescing (??)
Falls back only for null or undefined
Optional chaining (?.)
Short-circuits to undefined instead of throwing
Logical assignment (||=, &&=, ??=)
Combines a logical operator with assignment
Comma operator
Evaluates each operand, returns the last one
Labeled statement
Names a loop so break/continue can target it
'use strict'
Opts into stricter parsing and error handling
Hoisting
Declarations are moved to the top of their scope
Temporal dead zone
The span where a let/const exists but cannot be read
Block scope
A variable visible only within its enclosing { }
IIFE
A function expression invoked immediately: (() => {})()
Strict equality (===)
Compares value and type, no coercion
Loose equality (==)
Compares after coercing operands to a common type
Truthy / falsy
Values that coerce to true/false in a boolean context
Symbol
A unique, immutable primitive often used as an object key
BigInt
Integers of arbitrary precision, suffixed with n
Function declaration
function name() {} — hoisted, callable before its definition
Function expression
const fn = function () {} — not hoisted like a declaration
Arrow function
Concise syntax that inherits this from its enclosing scope
Default parameters
Fallback value used when an argument is undefined
Closure
A function bundled with variables from its outer scope
Higher-order function
A function that takes or returns another function
Callback
A function passed to run later, often after async work
Recursion
A function that calls itself to solve a smaller subproblem
Generator function
function* — pauses/resumes with yield, returns an iterator
yield
Pauses a generator and produces one value at a time
this
The context a function is called with — depends on how, not where, it is called
.bind()
Returns a new function with this permanently fixed
.call()
Invokes a function immediately with a given this and arguments
.apply()
Like .call(), but arguments are passed as an array
arguments
Array-like object of all arguments, in non-arrow functions
Pure function
Same input always gives the same output, no side effects
Currying
Splitting a multi-argument function into a chain of one-argument ones
Memoization
Caching a function’s results by its arguments
Debounce
Delays a call until activity has stopped for a set time
Throttle
Limits a function to running at most once per interval
.push() / .pop()
Add/remove the last element — mutates the array
.shift() / .unshift()
Remove/add the first element — mutates the array
.splice()
Removes and/or inserts elements at a given index, in place
.slice()
Returns a shallow copy of a portion, without mutating
.concat()
Merges arrays into a new array, without mutating
.join()
Joins all elements into a string with a separator
.reverse()
Reverses an array in place
.sort()
Sorts in place — as strings unless a compare function is given
.map()
Returns a new array with each element transformed
.filter()
Returns a new array of elements passing a test
.reduce()
Folds an array down to a single accumulated value
.forEach()
Runs a callback for each element, returns undefined
.find()
Returns the first element passing a test, or undefined
.findIndex()
Returns the index of the first match, or -1
.some()
True if at least one element passes a test
.every()
True only if every element passes a test
.includes()
True if the array contains a given value
.indexOf()
Index of the first matching value, or -1
.flat()
Flattens nested arrays to a given depth
.flatMap()
Maps then flattens one level — cheaper than the two separately
.at()
Indexes an array, allowing negative numbers from the end
.fill()
Fills a range of elements with a static value, in place
Array.from()
Builds a real array from an iterable or array-like value
Array.isArray()
True if the value is an array (typeof cannot tell)
Array.of()
Creates an array from its arguments, unlike Array(n)
.entries() / .keys() / .values()
Iterators over index/value pairs, indices, or values
Array destructuring
const [a, b] = arr — unpacks by position
Sparse array
An array with holes — indices that were never assigned
Object.keys()
Returns an array of an object’s own enumerable keys
Object.values()
Returns an array of an object’s own enumerable values
Object.entries()
Returns [key, value] pairs as an array
Object.fromEntries()
Builds an object back from [key, value] pairs
Object.assign()
Copies enumerable properties from sources into a target
Object.freeze()
Prevents any further changes to an object
Object.seal()
Prevents adding/removing keys, but existing ones stay writable
Object.create()
Creates a new object with a given prototype
Object.is()
Like ===, but correctly distinguishes NaN and -0
hasOwnProperty()
True if a key exists directly on the object, not inherited
in operator
True if a key exists anywhere in the prototype chain
delete
Removes a property from an object
Computed property
{ [expr]: value } — a key built from an expression
Shorthand property
{ name } instead of { name: name }
Object spread ({...obj})
Copies an object’s own enumerable properties into a new one
Prototype
The object another object inherits properties from
__proto__
Legacy accessor for an object’s prototype — prefer Object.getPrototypeOf
Map
Key-value pairs with any key type, in insertion order
Set
A collection of unique values
WeakMap / WeakSet
Like Map/Set, but keys are garbage-collected when unreferenced elsewhere
Promise
Represents a value that will be available later
.then()
Registers a callback for when a promise fulfills
.catch()
Registers a callback for when a promise rejects
.finally()
Runs regardless of whether the promise fulfilled or rejected
async
Marks a function as always returning a promise
await
Pauses an async function until a promise settles
Promise.all()
Resolves when every promise resolves, rejects on the first failure
Promise.allSettled()
Always resolves, with the outcome of every promise
Promise.race()
Settles as soon as the first promise settles
Promise.any()
Resolves on the first success, rejects only if all fail
setTimeout()
Runs a callback once after a delay
setInterval()
Runs a callback repeatedly on a fixed interval
clearTimeout() / clearInterval()
Cancels a pending timeout/interval
fetch()
Makes an HTTP request, returning a promise of the response
try / catch / finally
Runs code, handles thrown errors, then cleans up regardless
throw
Raises an error, unwinding the stack to the nearest catch
Error
The base error type — has message, name and stack
Custom errors
class MyError extends Error — errors with domain-specific data
Microtask queue
Where promise callbacks run, before the next macrotask
Event loop
The mechanism that interleaves sync code, microtasks and macrotasks
document.querySelector()
Returns the first element matching a CSS selector
document.querySelectorAll()
Returns a static NodeList of all matches
document.getElementById()
Returns the element with a given id, or null
document.createElement()
Creates a new, detached element node
.appendChild() / .append()
Adds a node as the last child of an element
.removeChild() / .remove()
Removes a child node, or the element itself
addEventListener()
Attaches a callback to run when an event fires
removeEventListener()
Detaches a previously attached listener
event.preventDefault()
Cancels the browser’s default action for an event
event.stopPropagation()
Stops an event from bubbling to ancestor elements
classList
Add/remove/toggle CSS classes without string manipulation
dataset
Reads/writes data-* attributes as a plain object
innerHTML
Reads/writes an element’s markup — parses the string as HTML
textContent
Reads/writes text only, always safe from injection
.closest()
Finds the nearest ancestor (or self) matching a selector
.matches()
Tests whether an element matches a CSS selector
Event bubbling
An event travels from the target up through its ancestors
Event capturing
An event travels from the root down to the target first
Event delegation
One listener on a parent handles events from all its children
DOMContentLoaded
Fires once the HTML is parsed, before images/styles finish loading
class
Syntax sugar over prototypes for defining a type
constructor
Runs once when a class is instantiated with new
extends
Declares that one class inherits from another
super
Calls the parent constructor or a parent method
static
A member that belongs to the class itself, not instances
get / set
Defines a property that runs code on read/write
#privateField
A field genuinely inaccessible outside the class
new
Creates a new instance, running the constructor
instanceof
Tests whether an object was created by a given class
Prototype chain
The lookup path the engine follows to find inherited members
Mixin
A function that adds shared behavior to a class
Abstract-style base class
A base class meant only to be extended, never instantiated directly
export
Makes a value available to other modules
export default
The one primary export of a module, imported without braces
import
Brings exported values from another module into scope
import * as
Imports every export of a module as one namespace object
Dynamic import()
Loads a module on demand, returning a promise
JSON.stringify()
Serializes a value to a JSON string
JSON.parse()
Parses a JSON string back into a value
Number.isInteger()
True only for whole numbers, no coercion
Number.isNaN()
True only for the actual NaN value, unlike global isNaN()
parseInt() / parseFloat()
Parses a leading numeric portion out of a string
Math object
Static methods/constants: Math.max, Math.random, Math.floor, etc.
console.log() / table() / group()
The console’s logging, tabular, and grouping output methods
Date
Represents a single moment in time
RegExp
A pattern for matching and extracting text
.test() / .exec()
Runs a regular expression against a string
String.prototype.match() / .replace()
Finds or replaces text, often using a regular expression

Worked examples with live previews, for the parts worth seeing in action.

Syntax & Variables

let, const & var

const name = 'Ada'; // reassignment throws
const user = { name: 'Ada' };
user.name = 'Grace'; // fine — the binding is const, the object isn't frozen

let count = 0;
count += 1; // fine — let can be reassigned

if (true) {
  let scoped = 'inside';
  var leaky = 'also inside';
}
// scoped is not visible here — leaky is (var ignores the block)

console.log(typeof hoisted); // "undefined", not an error
var hoisted = 'declaration is hoisted, the assignment is not';

Block scoping replaced function scoping — const by default, let when it needs to change.

const
Can't be reassigned — but an object/array it holds can still be mutated
let
Block-scoped, reassignable — the default when a value needs to change
var
Function-scoped, hoisted with value undefined — avoid in new code
TDZ
let/const exist but throw if read before their declaration line runs
  • let
  • const
  • var
  • scope
  • hoisting
  • temporal dead zone

Destructuring & Template Literals

const user = { name: 'Ada', age: 36, role: 'engineer' };
const { name, age, role: title = 'member' } = user;

const [first, second, ...rest] = [1, 2, 3, 4, 5];
// first = 1, second = 2, rest = [3, 4, 5]

function greet({ name, age }) {
  return `${name} is ${age} years old`; // template literal — embeds expressions directly
}

const html = `
  <ul>
    ${['a', 'b'].map((item) => `<li>${item}</li>`).join('')}
  </ul>
`;

Pull values out of arrays and objects by shape; build strings by embedding expressions.

  • destructuring
  • template literals
  • string interpolation
  • tagged templates

Functions

Arrow Functions & Closures

function makeCounter() {
  let count = 0; // captured by the closure below
  return {
    increment: () => ++count,
    value: () => count,
  };
}

const counter = makeCounter();
counter.increment();
counter.increment();
counter.value(); // 2 — each counter keeps its own private `count`

class Timer {
  seconds = 0;
  start() {
    // arrow function keeps `this` bound to the Timer instance
    setInterval(() => this.seconds++, 1000);
  }
}

Arrow functions inherit this from where they are written; closures remember the scope they were created in.

Arrow functions
Do not have their own this — they use the this of the enclosing scope
Closure
A function bundled with the variables it can still access from an outer scope
No arguments object
Arrow functions have no own arguments — use a rest parameter instead
  • arrow function
  • closure
  • this
  • lexical scope

Default, Rest & Spread Parameters

function createUser(name, role = 'member') {
  // role falls back to 'member' only when the argument is undefined
  return { name, role };
}

function sum(...numbers) {
  // rest parameter — gathers any number of arguments into a real array
  return numbers.reduce((total, n) => total + n, 0);
}
sum(1, 2, 3, 4); // 10

const scores = [88, 92, 79];
Math.max(...scores); // spread — expands the array into individual arguments

const combined = [...scores, 100]; // spread also copies/extends arrays
const merged = { ...{ a: 1 }, ...{ b: 2 } }; // and objects

Fallback values for missing arguments, gathering the rest into an array, and expanding an array into arguments.

  • default parameters
  • rest parameters
  • spread
  • arguments

Arrays

Array Methods Playground

Swap the method and edit the array — watch the transformation run live.

input
output

  • array
  • playground
  • interactive
  • map
  • filter
  • reduce

Transformation Methods

const orders = [
  { id: 1, total: 42, paid: true },
  { id: 2, total: 15, paid: false },
  { id: 3, total: 99, paid: true },
];

const totals = orders.map((o) => o.total); // [42, 15, 99]
const unpaid = orders.filter((o) => !o.paid); // [{ id: 2, ... }]
const revenue = orders.filter((o) => o.paid).reduce((sum, o) => sum + o.total, 0); // 141

const firstBigOrder = orders.find((o) => o.total > 50); // the order with id 3
const allPaid = orders.every((o) => o.paid); // false
const anyUnpaid = orders.some((o) => !o.paid); // true

map, filter and reduce cover almost everything — chain them instead of reaching for a loop.

map
Same length in and out — one output value per input value
filter
Keeps items where the callback returns true — length can shrink
reduce
Folds the array down to a single value of any shape
find / some / every
Stop early — find returns the item, some/every return a boolean
  • map
  • filter
  • reduce
  • find
  • some
  • every
  • forEach

Mutating vs Non-Mutating Methods

const original = [3, 1, 2];

// mutating — original is changed, and reused elsewhere this can surprise you
original.push(4); // [3, 1, 2, 4]
original.sort(); // [1, 2, 3, 4] — but sorts lexicographically without a comparator!
[10, 2, 1].sort(); // [1, 10, 2] — not what you probably wanted

// non-mutating — safer when other code might hold a reference to the array
const numeric = [10, 2, 1].sort((a, b) => a - b); // [1, 2, 10]
const copy = [...original, 5]; // original is untouched
const withoutFirst = original.slice(1); // new array, original unchanged

Half of the array methods change the array in place — the other half return a new one.

Mutates in place
push, pop, shift, unshift, splice, sort, reverse — all change the original array
Returns a new array
slice, concat, map, filter, spread [...arr] — the original is left untouched
sort() gotcha
Sorts as strings by default — pass a compare function for numbers
  • push
  • pop
  • splice
  • sort
  • slice
  • concat
  • immutable
  • mutation

Objects

Object Shorthand & Spread

const name = 'Ada';
const age = 36;
const user = { name, age }; // shorthand — same as { name: name, age: age }

const key = 'role';
const withRole = { ...user, [key]: 'engineer' }; // computed key + spread copy

const defaults = { theme: 'dark', pageSize: 10 };
const overrides = { pageSize: 25 };
const merged = { ...defaults, ...overrides }; // { theme: 'dark', pageSize: 25 } — later keys win

for (const [key, value] of Object.entries(user)) {
  console.log(key, value);
}

Object.keys(user); // ['name', 'age']
Object.values(user); // ['Ada', 36]
Object.fromEntries([['a', 1], ['b', 2]]); // { a: 1, b: 2 }

Shorthand properties, computed keys, and copying/merging objects with spread.

  • object
  • spread
  • shorthand
  • computed property
  • Object.entries

Optional Chaining & Nullish Coalescing

const user = { profile: { social: null } };

user.profile.social.twitter; // throws: Cannot read properties of null
user.profile?.social?.twitter; // undefined — no throw
user.profile?.getBio?.(); // undefined — safely skips calling a method that does not exist

const settings = { retries: 0, name: '' };
settings.retries || 5; // 5 — wrong! 0 is falsy, so || overrides it
settings.retries ?? 5; // 0 — right — ?? only falls back for null/undefined
settings.name ?? 'Anonymous'; // '' — kept, because '' is not null/undefined

Safely read deeply nested properties, and fall back only for null or undefined — not every falsy value.

?.
Short-circuits to undefined instead of throwing if anything along the chain is null/undefined
??
Falls back only for null or undefined — unlike ||, it keeps 0, "" and false
?.()
Optionally calls a function — only invokes it if it actually exists
  • optional chaining
  • nullish coalescing
  • ?.
  • ??
  • falsy

Async & Promises

Promises

function fetchUser(id) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (id > 0) resolve({ id, name: 'Ada' });
      else reject(new Error('invalid id'));
    }, 300);
  });
}

fetchUser(1)
  .then((user) => user.name)
  .then((name) => console.log(name.toUpperCase()))
  .catch((err) => console.error('failed:', err.message))
  .finally(() => console.log('request finished'));

A Promise represents a value that is not ready yet — pending, then fulfilled or rejected, exactly once.

pending -> fulfilled/rejected
A promise settles exactly once and never changes state again
.then / .catch
Register callbacks for success and failure — both return a new promise
.finally
Runs regardless of outcome — cleanup that should always happen
  • promise
  • then
  • catch
  • finally
  • async

async / await

async function loadProfile(id) {
  try {
    const response = await fetch(`/api/users/${id}`);
    if (!response.ok) throw new Error(`request failed: ${response.status}`);

    const user = await response.json();
    return user;
  } catch (err) {
    console.error('could not load profile:', err.message);
    return null;
  }
}

// an async function always returns a promise, even if you return a plain value
loadProfile(1).then((user) => console.log(user));

// sequential — each await waits before starting the next
async function loadBoth() {
  const a = await loadProfile(1);
  const b = await loadProfile(2);
  return [a, b];
}

Write asynchronous code that reads top-to-bottom — await pauses the function until the promise settles.

  • async
  • await
  • try catch
  • fetch

Promise.all, race, allSettled & any

const requests = [loadProfile(1), loadProfile(2), loadProfile(3)];

const users = await Promise.all(requests);
// all three ran concurrently, not one after another — much faster than sequential awaits

const results = await Promise.allSettled(requests);
// [{ status: 'fulfilled', value: ... }, { status: 'rejected', reason: ... }, ...]
// never throws — good for "load as much as you can"

const fastest = await Promise.race([
  fetchUser(1),
  new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), 2000)),
]);

Run several promises together instead of one at a time — pick the combinator by how you need failures handled.

Promise.all
Resolves with all results — rejects immediately if any one promise rejects
Promise.allSettled
Always resolves — gives you the outcome of every promise, failures included
Promise.race
Settles as soon as the first promise settles, win or lose
Promise.any
Resolves on the first success — only rejects if every promise rejects
  • Promise.all
  • Promise.race
  • Promise.allSettled
  • Promise.any
  • concurrent

DOM & Events

Selecting & Modifying Elements

const card = document.querySelector('.card');
const allButtons = document.querySelectorAll('button');

card.classList.add('active');
card.classList.toggle('collapsed');
card.classList.contains('active'); // true

card.textContent = 'Plain text, always escaped'; // safe
card.innerHTML = '<strong>Parsed as markup</strong>'; // only with trusted content

card.dataset.userId; // reads data-user-id="..."
card.dataset.status = 'ready'; // writes data-status="ready"

card.style.setProperty('--accent', '#38e0e0'); // set a CSS custom property directly

Find elements with querySelector, then read or change them through the same handful of properties.

querySelector / querySelectorAll
Any CSS selector works — the All version returns a static NodeList
textContent vs innerHTML
textContent is always safe from injection; innerHTML parses the string as markup
dataset
Reads/writes data-* attributes as a plain object — data-user-id becomes dataset.userId
  • querySelector
  • classList
  • textContent
  • dataset
  • DOM

Event Listeners & Delegation

const list = document.querySelector('.todo-list');

// one listener on the parent covers every item, including ones added later
list.addEventListener('click', (event) => {
  const item = event.target.closest('.todo-item');
  if (!item) return; // click landed somewhere else inside .todo-list

  if (event.target.matches('.delete-button')) {
    item.remove();
  }
});

document.querySelector('form').addEventListener('submit', (event) => {
  event.preventDefault(); // stop the native page reload
  console.log('submitting without a full page navigation');
});

const controller = new AbortController();
window.addEventListener('scroll', onScroll, { signal: controller.signal });
controller.abort(); // removes the listener — no need to keep a reference to onScroll

Listen on a parent instead of every child — the event still tells you exactly what was clicked.

  • addEventListener
  • event delegation
  • preventDefault
  • closest

Classes

Class Syntax & Inheritance

class Shape {
  constructor(name) {
    this.name = name;
  }
  describe() {
    return `${this.name} has an area of ${this.area()}`;
  }
  area() {
    return 0; // overridden by subclasses
  }
}

class Circle extends Shape {
  constructor(radius) {
    super('Circle'); // must run before using `this` in a subclass constructor
    this.radius = radius;
  }
  area() {
    return Math.PI * this.radius ** 2;
  }
}

const circle = new Circle(4);
circle.describe(); // "Circle has an area of 50.26..."
circle instanceof Shape; // true

Syntax sugar over prototypes — constructor, methods, and extends for sharing behavior between classes.

  • class
  • constructor
  • extends
  • super
  • inheritance

Getters, Setters & Private Fields

class BankAccount {
  #balance; // private — no code outside this class can reach account.#balance

  constructor(openingBalance) {
    this.#balance = openingBalance;
  }

  get balance() {
    return this.#balance; // reads like account.balance, no parentheses
  }

  set balance(amount) {
    if (amount < 0) throw new Error('balance cannot go negative');
    this.#balance = amount;
  }

  static openWithBonus() {
    return new BankAccount(50); // called as BankAccount.openWithBonus()
  }
}

const account = new BankAccount(100);
account.balance; // 100 — via the getter
account.balance = 150; // via the setter
account.#balance; // SyntaxError outside the class

Compute a property on access, validate it on write, and hide implementation details with #.

#field
Truly private — inaccessible outside the class, even from a subclass
get / set
Read/write like a normal property while running code behind the scenes
static
Belongs to the class itself, not to individual instances
  • get
  • set
  • private fields
  • static
  • #

Modules & Tooling

import & export

// math.js
export function add(a, b) {
  return a + b;
}
export const PI = 3.14159;
export default function multiply(a, b) {
  return a * b;
}
// app.js
import multiply, { add, PI } from './math.js';
import * as math from './math.js'; // everything, namespaced

add(2, 3); // 5
multiply(2, 3); // 6
math.PI; // 3.14159

ES modules split code into files with their own scope — named exports for utilities, default for the main thing.

Named export
export { formatDate } — imported with the exact same name, in braces
Default export
One per file — imported under any name you choose, no braces
Module scope
Everything not exported stays private to that file automatically
  • import
  • export
  • default export
  • named export
  • modules

JSON & Type Checking

const user = { name: 'Ada', tags: ['admin', 'beta'] };

const json = JSON.stringify(user); // '{"name":"Ada","tags":["admin","beta"]}'
const restored = JSON.parse(json); // back to a real object

typeof 'text'; // "string"
typeof 42; // "number"
typeof undefined; // "undefined"
typeof null; // "object" — a famous, long-standing quirk

Array.isArray([1, 2, 3]); // true — typeof an array is just "object"
[] instanceof Array; // true

new Date() instanceof Date; // true
Number.isInteger(4.0); // true
Number.isNaN(Number('not a number')); // true — safer than the global isNaN()

Serialize data for storage or a network request, and check what you actually got back.

  • JSON
  • typeof
  • instanceof
  • Array.isArray
  • JSON.parse
  • JSON.stringify
webcheet

↑↓ navigate↵ openesc close