Skip to content
AchillesBackend developer

Modern JavaScript cheat sheet

2020updated 20267 min read#javascript

ON THIS PAGE

A cheat sheet of the modern JavaScript I reach for. Destructuring, arrow functions, array methods, modules, promises and async/await.

A cheat sheet of the JavaScript I actually write, from ES2015 to ES2025. One short example per feature, no theory. Everything here runs in current browsers and Node 24.

Declaring variables

let

The let keyword declares block-scoped variables in contrast to the var keyword which declares function-scoped or global variables.

const

The const keyword declares block-scoped constants.

Destructuring assignment

javascript
let { bar } = foo // where foo = { bar:10, baz:12 };
const { baz } = foo // where foo = { bar:10, baz:12 };

// with a default value
const { qux = 0 } = foo // qux = 0

// arrays, with the rest
const [first, ...rest] = [1, 2, 3] // first = 1, rest = [2, 3]

Strings

Template literals

javascript
const name = 'Achilles'
const greeting = `Hello ${name}` // "Hello Achilles"

Arrow functions

javascript
// No semicolons here, so a line that starts with ( or [ would continue
// the line before it. Start such a line with ; when it follows a statement.

// 1. Typical arrow function.
(a, b) => {
  return a + b
}

// 2. One-liner without braces, the return is implied.
(a, b) => a + b

// 3. With one argument the parentheses can be removed.
a => a + 1

// 4. Return an object, wrap it in parentheses.
const toUser = (name) => ({ name })

Arrow functions and this

Arrow functions have no this of their own. They use the this of the code around them, which is what you want in callbacks.

javascript
const timer = {
  seconds: 0,
  start() {
    setInterval(() => {
      this.seconds++ // arrow functions use the `this` of the surrounding code, here the timer
    }, 1000)
  },
}

Objects

Spread

javascript
const defaults = { theme: 'light', lang: 'en' }
const settings = { ...defaults, theme: 'dark' } // { theme: 'dark', lang: 'en' }

Optional chaining

javascript
const user = { name: 'Achilles', address: null }

user.address?.city // undefined instead of a TypeError
user.getName?.() // calls getName only if it exists

Nullish coalescing

javascript
const count = 0

count || 10 // 10, because 0 is falsy
count ?? 10 // 0, only null and undefined fall back

let limit
limit ??= 25 // assigns only if limit is null or undefined

Deep copy with structuredClone

javascript
const original = { tags: ['php'], created: new Date() }
const copy = structuredClone(original) // a deep copy, Dates and Maps included

copy.tags.push('js') // original.tags is still ['php']

Object.entries() and Object.fromEntries()

javascript
const prices = { tea: 2, coffee: 3 }

const doubled = Object.fromEntries(
  Object.entries(prices).map(([item, price]) => [item, price * 2]),
) // { tea: 4, coffee: 6 }

Arrays

array.map()

Returns a new array populated with the results of the provided function for each iteration:

javascript
const newItems = items.map((x) => x + 1)

array.filter()

Returns a new array populated with filtered results which return true in the provided function.

javascript
const filteredItems = items.filter((item) => item.length > 3)

array.slice()

Returns a copy of a portion of an array.

javascript
const newItems = items.slice(2, 4)

Copy an array

javascript
// Use the spread operator. This is a shallow copy, nested objects are shared (see structuredClone).
const newArray = [...oldArray]

Array.from()

Creates an array from array-like objects.

javascript
Array.from([1, 2, 3], (x) => x + x) // [2, 4, 6]

// array-like objects and iterables
Array.from('abc') // ['a', 'b', 'c']
Array.from({ length: 3 }, (_, i) => i) // [0, 1, 2]

array.find()

Returns the value of the first element that matches the conditions in the provided callback function.

javascript
const foundItem = items.find((item) => item.id === 3)

array.findLast()

The same as find(), starting from the end.

javascript
const users = [{ name: 'A', admin: true }, { name: 'B', admin: true }, { name: 'C' }]
const lastAdmin = users.findLast((user) => user.admin) // { name: 'B', admin: true }

array.at() and array.includes()

javascript
const letters = ['a', 'b', 'c']

letters.at(-1) // 'c', negative indexes count from the end
letters.includes('b') // true

array.flat()

javascript
const flat = [[1, 2], [3]].flat() // [1, 2, 3]

toSorted(), toReversed() and with()

Like sort(), reverse() and array[i] = x, but they return a new array and leave the original alone.

javascript
const numbers = [3, 1, 2]

const sorted = numbers.toSorted((a, b) => a - b) // [1, 2, 3]
const reversed = numbers.toReversed() // [2, 1, 3]
const replaced = numbers.with(0, 9) // [9, 1, 2]
// numbers is still [3, 1, 2]

Without the compare function, toSorted() and sort() compare values as strings, so [10, 9] stays [10, 9].

Object.groupBy()

javascript
const posts = [
  { title: 'Git reflog', tag: 'git' },
  { title: 'Linux 101', tag: 'linux' },
  { title: 'My Git cheat sheet', tag: 'git' },
]

const byTag = Object.groupBy(posts, (post) => post.tag)
// { git: [two posts], linux: [one post] }

Sets

javascript
const backend = new Set(['php', 'sql'])
const frontend = new Set(['js', 'sql'])

backend.union(frontend) // Set { 'php', 'sql', 'js' }
backend.intersection(frontend) // Set { 'sql' }
backend.difference(frontend) // Set { 'php' }

const unique = [...new Set([1, 1, 2])] // [1, 2]

Loops

for…of

Loops through iterable objects including arrays.

javascript
const array = [1, 2, 3]

for (const item of array) {
  console.log(item)
}

// with the index
for (const [index, item] of array.entries()) {
  console.log(index, item)
}

forEach

You can’t stop a forEach. return only skips to the next item, and break is a SyntaxError. Use for...of or some() when you need to stop early.

javascript
array.forEach(function (item) {
  console.log(item)
})

for…in

Loop through object properties. Avoid using for...in with arrays.

javascript
const object = { a: 1, b: 2, c: 3 }

for (const property in object) {
  console.log(property)
}

Classes

javascript
class Car extends Vehicle {
  constructor(name) {
    super() // Call the parent constructor.
    this.name = name
  }

  changeName(name) {
    this.name = name
  }
}

const car1 = new Car("BMW")

Private and static fields

javascript
class Counter {
  #count = 0 // private field
  static instances = 0 // static field

  constructor() {
    Counter.instances++
  }

  increment() {
    return ++this.#count
  }

  get value() {
    return this.#count
  }
}

const counter = new Counter()
counter.increment() // 1
counter.value // 1
// counter.#count outside the class is a SyntaxError

Modules

Native modules in the browser and in Node need the file extension in the import path.

Named exports

javascript
// Named export.
export class Car extends Vehicle {}

// Named import.
import { Car } from "./car.js"

Default exports

javascript
// Default export.
export default class Car extends Vehicle {}

// Default import.
import Car from "./car.js"

Dynamic import

javascript
// Load a module only when it is needed.
const { Car } = await import("./car.js")

Top-level await

javascript
// In a module, await works outside async functions.
const config = await fetch('/config.json').then((response) => response.json())

Promises

Basics

javascript
let promise = new Promise(function(resolve, reject) {
  // async logic ...

  if (everythingIsOk) {
    resolve("Success!");
  }
  else {
    reject("Something went wrong!");
  }
});

promise.then((message) => {
  // do something.
}).catch((message) => {
 // do something with the error.
})

Promise.all

Waits for several promises at once.

javascript
Promise.all([promise1, promise2, promise3]).then((messages) => {
  // messages is an array with the results, in the same order.
  // It resolves when all the promises have resolved,
  // and rejects as soon as one of them rejects.
})

Promise.allSettled

Waits for all of them, whether they resolve or reject.

javascript
const results = await Promise.allSettled([promise1, promise2])
// [{ status: 'fulfilled', value: ... }, { status: 'rejected', reason: ... }]

Promise.any

javascript
// Resolves with the first promise that fulfills, rejects only if all of them reject.
const fastest = await Promise.any([fetchFromMirror1(), fetchFromMirror2()])

Async/await

javascript
async function doStuff() {
  try {
    // Waits for the resolved promise value.
    let result = await asyncFunction()
  } catch (error) {
    // Get the rejected promise value.
  }
}

fetch with a timeout

javascript
const response = await fetch(url, {
  signal: AbortSignal.timeout(5000), // give up after 5 seconds
})
if (!response.ok) throw new Error(`HTTP ${response.status}`)
const posts = await response.json()
Did this help?

Comments

via GitHub Discussions