JavaScript Idioms — ES2022 (DSA)
Examples target ES2022 features only (no newer syntax). No single-letter variable names.
Map / Set vs object for frequency counts
Prefer Map when keys are arbitrary (including non-strings), insertion order matters for iteration strategy, or you avoid prototype pollution. Set for existence / uniqueness.
const frequencies = new Map();
const tokens = ['a', 'b', 'a'];
for (const token of tokens) {
frequencies.set(token, (frequencies.get(token) ?? 0) + 1);
}Plain objects are fine for string-only keys and JSON-shaped payloads; use Object.hasOwn (ES2022) for safe checks.
const counts = Object.create(null);
const letter = 'x';
counts[letter] = (counts[letter] ?? 0) + 1;Array methods: reduce sparingly
reduce is powerful but often less readable than a simple loop for accumulators. Prefer for...of when the reducer body grows.
const values = [1, 2, 3];
let total = 0;
for (const value of values) {
total += value;
}When reduce stays one clear fold, it is fine:
const values = [1, 2, 3];
const product = values.reduce((accumulator, value) => accumulator * value, 1);BigInt when needed
Use BigInt when integers exceed Number.MAX_SAFE_INTEGER or exact integer semantics matter.
const huge = BigInt('9007199254740993');
const doubled = huge * 2n;
console.log(doubled.toString());Mixing BigInt and Number in arithmetic throws—convert explicitly.
Bitwise >>> for unsigned 32-bit
>>> zero-fills; use for unsigned 32-bit patterns (hash mixes, competitive tricks).
const signed = -1;
const unsigned = signed >>> 0;
console.log(unsigned);Avoid sparse arrays
Sparse arrays (non-contiguous indices) surprise map/length behavior and hurt performance. Fill explicitly or use Map from index → value.
const dense = [];
dense[0] = 'a';
dense[1] = 'b';
console.log(dense.length);Spread and copy pitfalls
Spread is shallow: nested objects/arrays still alias.
const outer = [{ value: 1 }];
const clone = [...outer];
clone[0].value = 99;
console.log(outer[0].value);For JSON-safe deep copies (no cycles, no BigInt/functions):
const tree = { left: null, right: { value: 2 } };
const duplicate = JSON.parse(JSON.stringify(tree));Custom nodes need a manual clone or library—DSA templates often only need shallow array copies.
MinHeap class pattern (heapify / top-k style)
class MinHeap {
constructor() {
this.items = [];
}
push(value) {
this.items.push(value);
this.#bubbleUp(this.items.length - 1);
}
pop() {
if (this.items.length === 0) return undefined;
const root = this.items[0];
const last = this.items.pop();
if (this.items.length > 0 && last !== undefined) {
this.items[0] = last;
this.#bubbleDown(0);
}
return root;
}
peek() {
return this.items[0];
}
#parentIndex(index) {
return Math.floor((index - 1) / 2);
}
#bubbleUp(index) {
let current = index;
while (current > 0) {
const parent = this.#parentIndex(current);
if (this.items[current] >= this.items[parent]) break;
[this.items[current], this.items[parent]] = [this.items[parent], this.items[current]];
current = parent;
}
}
#bubbleDown(index) {
const length = this.items.length;
let current = index;
while (true) {
const left = current * 2 + 1;
const right = left + 1;
let smallest = current;
if (left < length && this.items[left] < this.items[smallest]) smallest = left;
if (right < length && this.items[right] < this.items[smallest]) smallest = right;
if (smallest === current) break;
[this.items[current], this.items[smallest]] = [this.items[smallest], this.items[current]];
current = smallest;
}
}
}
const heap = new MinHeap();
heap.push(3);
heap.push(1);
heap.push(2);
console.log(heap.pop(), heap.pop(), heap.pop());Typed loops: for...of / for await
const items = [10, 20, 30];
for (const item of items) {
console.log(item);
}
async function loadLines() {
async function* streamChunks() {
yield 'a\n';
yield 'b';
}
for await (const chunk of streamChunks()) {
console.log(chunk);
}
}
void loadLines();See also: Data structure operations, Pattern recognition cheatsheet.
Last updated on
Spotted something unclear or wrong on this page?