Algorithms#
Most everyday algorithmic work uses methods on Array (and friends) plus a
few small helpers.
Sorting#
Array.prototype.sort is in-place and stable (since ES2019). The default
comparator coerces to strings, so always pass one for numbers.
const xs = [10, 2, 33, 4];
xs.sort(); // ["10","2","33","4"] order
xs.sort((a, b) => a - b); // [2, 4, 10, 33]
people.sort((a, b) => a.age - b.age);
For an immutable sort, use toSorted (ES2023) or [...xs].sort(cmp).
Search#
Linear scan.
const i = xs.indexOf(target);
const rec = users.find((u) => u.id === id);
const ok = users.some((u) => u.admin);
Binary search on a sorted array.
function binarySearch(xs, target) {
let lo = 0, hi = xs.length;
while (lo < hi) {
const mid = (lo + hi) >>> 1;
if (xs[mid] === target) return mid;
if (xs[mid] < target) lo = mid + 1;
else hi = mid;
}
return -1;
}
Map / Filter / Reduce#
const total = orders
.filter((o) => o.status === "paid")
.map((o) => o.amount)
.reduce((a, b) => a + b, 0);
const byCustomer = orders.reduce((acc, o) => {
(acc[o.customerId] ??= []).push(o);
return acc;
}, {});
Recursion#
function fact(n) {
return n <= 1 ? 1 : n * fact(n - 1);
}
For repeated work, memoise.
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);
};
}
Linked List#
class Node {
constructor(value, next = null) {
this.value = value;
this.next = next;
}
}
function push(head, value) {
return new Node(value, head);
}
Concurrency#
JavaScript is single-threaded, but I/O is concurrent. Use Promise.all
for parallel awaits, Promise.allSettled to keep going past failures,
and Promise.race for “first wins”.
const responses = await Promise.all(urls.map((u) => fetch(u)));
const bodies = await Promise.all(responses.map((r) => r.text()));