JavaScript#

Shortcut keys for the JavaScript interactive interpreters the operator reaches for: Node.js REPL (node), the Chrome / Edge DevTools Console, and Firefox Web Console. The Node REPL uses Node’s own readline implementation; DevTools consoles add Monaco-style editing on top of the page’s runtime. Bun and Deno have their own REPLs that overlap with Node’s bindings.

For setup, package managers (npm / pnpm / yarn / bun), and runtime configuration, see JavaScript.

Cursor Movement (Node)#

Key

Action

Ctrl-a

move to start of line

Ctrl-e

move to end of line

Ctrl-b / Left

move back one character

Ctrl-f / Right

move forward one character

Alt-b

move back one word

Alt-f

move forward one word

Editing (Node)#

Key

Action

Ctrl-d

delete character under cursor (or exit if line is empty)

Backspace / Ctrl-h

delete character before cursor

Alt-d

delete word forward

Ctrl-w

delete word backward

Ctrl-k

kill to end of line

Ctrl-u

kill to start of line

Ctrl-y

yank (paste) last killed text

Ctrl-t

transpose characters

Alt-t

transpose words

Ctrl-_

undo (where the terminal supports it)

History (Node)#

Node persists REPL history at ~/.node_repl_history by default. Override with NODE_REPL_HISTORY=<path> or empty to disable.

Key

Action

Up / Ctrl-p

previous history entry

Down / Ctrl-n

next history entry

Ctrl-r

reverse incremental search

Alt-.

insert last argument of previous command

.history

print persistent history (REPL . command)

REPL Commands (Node)#

Node’s .-prefixed dot commands operate on the REPL itself rather than the JS runtime.

Command

Action

.help

list dot commands

.editor

enter multi-line editor mode

.break / Ctrl-c

abort current input (without exiting)

.clear

reset the REPL context

.exit / Ctrl-d

exit the REPL

.save <path>

save the REPL session to a file

.load <path>

load JS from a file into the session

_

reference the last evaluated expression

_error

reference the last thrown error

Process Control#

Key

Action

Ctrl-c

cancel current line (twice in a row to exit Node)

Ctrl-d

send EOF (exits the REPL on empty line)

Ctrl-l

clear screen

Ctrl-z

suspend Node (SIGTSTP)

DevTools Console (browser runtimes)#

The browser console accepts JS at a single-line input by default; Shift-Enter opens multi-line mode. Chromium and Firefox share most of the bindings.

Key

Action

Ctrl-Shift-j (Chromium)

open DevTools focused on the Console

Ctrl-Shift-i (Chromium / Firefox)

open DevTools (last-used panel)

Ctrl-Shift-k (Firefox)

open the Web Console

Enter

submit single-line expression

Shift-Enter

newline without submitting (multi-line mode)

Ctrl-Enter

submit multi-line block

Up / Down

browse expression history

Ctrl-l

clear console output (Chromium)

Tab

accept the inline ghost-text suggestion

Ctrl-Space

open completion menu

Ctrl-/

toggle line comment in multi-line mode

$_

reference last evaluated expression

$0$4

reference last five inspected DOM nodes

$('selector')

shorthand for document.querySelector

$$('selector')

shorthand for document.querySelectorAll

$x('xpath')

evaluate XPath against the document

copy(obj)

copy a value to the system clipboard

Node Inspector (Chrome DevTools attach)#

Run with node --inspect (start with inspector listening) or node --inspect-brk (break before user code). Open chrome://inspect in Chromium, attach to the target, and DevTools binds the standard debugger keys.

Key

Action

F8 / Ctrl-\

resume / pause execution

F10 / Ctrl-'

step over

F11 / Ctrl-;

step into

Shift-F11 / Ctrl-Shift-;

step out

Ctrl-b

toggle breakpoint on current line

Ctrl-Shift-f

search across loaded scripts

Ctrl-p

open script by name

debugger;

source-level breakpoint statement

Bun / Deno REPLs#

Same readline keymap as Node for the bindings above; the notable extras / differences:

Key / Command

Action

bun repl

start the Bun REPL

deno repl

start the Deno REPL

deno repl --eval 'expr'

pre-evaluate before opening the REPL

--unstable

enable unstable APIs in either REPL

Ctrl-c

abort current input (single press in Bun / Deno, two presses in Node)

Ctrl-d

exit the REPL

Config and Discovery#

Command / file

Action

NODE_REPL_HISTORY

path to Node REPL history file ("" disables)

~/.node_repl_history

default history file

NODE_REPL_HISTORY_SIZE

max entries in history

NODE_REPL_MODE

sloppy or strict (default sloppy)

node --use-strict

run REPL in strict mode

node --inspect

enable Chrome DevTools inspector

util.inspect.defaultOptions

customize how the REPL prints objects

readline.cursorTo / moveCursor

low-level readline API (when building your own REPL)

fetch With Timeout and Retry#

async function fetchJson(url, { timeout = 5000, retries = 3 } = {}) {
  for (let attempt = 0; attempt <= retries; attempt++) {
    const ac = new AbortController();
    const id = setTimeout(() => ac.abort(), timeout);
    try {
      const r = await fetch(url, { signal: ac.signal });
      if (!r.ok) throw new Error(`HTTP ${r.status}`);
      return await r.json();
    } catch (err) {
      if (attempt === retries) throw err;
      await new Promise((r) => setTimeout(r, 2 ** attempt * 200));
    } finally {
      clearTimeout(id);
    }
  }
}

Parallel With Concurrency Cap#

async function pool(items, n, fn) {
  const out = [];
  let i = 0;
  async function worker() {
    while (i < items.length) {
      const idx = i++;
      out[idx] = await fn(items[idx]);
    }
  }
  await Promise.all(Array.from({ length: n }, worker));
  return out;
}

Debounce / Throttle#

function debounce(fn, wait) {
  let t;
  return (...args) => {
    clearTimeout(t);
    t = setTimeout(() => fn(...args), wait);
  };
}

function throttle(fn, wait) {
  let last = 0;
  return (...args) => {
    const now = Date.now();
    if (now - last >= wait) {
      last = now;
      fn(...args);
    }
  };
}

Group By#

// ES2024 native
Object.groupBy(users, (u) => u.team);

// Manual
const byTeam = users.reduce((acc, u) => {
  (acc[u.team] ??= []).push(u);
  return acc;
}, {});

Deep Clone (Structured)#

const clone = structuredClone(obj);   // built in everywhere modern

Pick / Omit#

const pick = (obj, keys) =>
  Object.fromEntries(keys.filter((k) => k in obj).map((k) => [k, obj[k]]));

const omit = (obj, keys) =>
  Object.fromEntries(Object.entries(obj).filter(([k]) => !keys.includes(k)));

Sorting#

xs.sort((a, b) => a - b);                                 // numbers
ys.sort((a, b) => a.localeCompare(b));                    // strings, locale
people.sort((a, b) => a.lastName.localeCompare(b.lastName) ||
                       a.firstName.localeCompare(b.firstName));

Async Iteration#

for await (const chunk of response.body) {
  process(chunk);
}

// Async generator
async function* paginate(url) {
  let next = url;
  while (next) {
    const r = await fetch(next).then((r) => r.json());
    yield* r.items;
    next = r.next;
  }
}
for await (const item of paginate("/api/items")) {
  process(item);
}

Once#

function once(fn) {
  let called = false, result;
  return (...args) => {
    if (!called) {
      result = fn(...args);
      called = true;
    }
    return result;
  };
}

Memoize#

function memoize(fn) {
  const cache = new Map();
  return (...args) => {
    const key = JSON.stringify(args);
    if (!cache.has(key)) cache.set(key, fn(...args));
    return cache.get(key);
  };
}

Sleep#

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

await sleep(500);

Format Bytes / Duration#

const formatBytes = (n) => {
  if (n < 1024) return `${n} B`;
  const units = ["KB", "MB", "GB", "TB"];
  let i = -1;
  do { n /= 1024; i++; } while (n >= 1024 && i < units.length - 1);
  return `${n.toFixed(1)} ${units[i]}`;
};

// Intl is the right tool for most formatting
new Intl.NumberFormat("en-US").format(1234567);
new Intl.DateTimeFormat("en-US", { dateStyle: "medium" }).format(new Date());

URL Building#

const url = new URL("https://api.example.com/search");
url.searchParams.set("q", "operator");
url.searchParams.set("limit", "10");
await fetch(url);

EventEmitter / Pub-Sub#

class Emitter {
  #listeners = new Map();
  on(event, fn)   { (this.#listeners.get(event) ?? this.#listeners.set(event, new Set()).get(event)).add(fn); }
  off(event, fn)  { this.#listeners.get(event)?.delete(fn); }
  emit(event, ...args) {
    for (const fn of this.#listeners.get(event) ?? []) fn(...args);
  }
}

Type-Safe JSON Parse (TypeScript)#

import { z } from "zod";

const User = z.object({ id: z.number(), name: z.string() });
type User = z.infer<typeof User>;

async function fetchUser(id: number): Promise<User> {
  const r = await fetch(`/api/users/${id}`);
  if (!r.ok) throw new Error(`HTTP ${r.status}`);
  return User.parse(await r.json());
}