Sorting Algorithms in JavaScript
Implement sorting algorithms in JavaScript and learn how Array.prototype.sort() works, including the classic numeric-compare gotcha and V8's use of Tim Sort.
On this page +
Sorting in JavaScript has a famous gotcha that trips up beginners, plus a modern engine implementation worth understanding. This guide covers Array.prototype.sort(), the compare-function trap, and clean implementations of the classic algorithms.
The Array.sort gotcha #
By default, Array.prototype.sort() converts elements to strings and sorts lexicographically — so [10, 2, 1].sort() returns [1, 10, 2]! Always pass a compare function for numbers: arr.sort((a, b) => a - b). This is the single most common JavaScript sorting bug.
What engines use #
Since 2018, V8 (Chrome, Node.js) implements Array.prototype.sort() with Tim Sort. The ECMAScript spec has required sort to be stable since ES2019, so behavior on equal elements is now consistent across modern browsers. See JavaScript's Array.sort algorithm for more.
Quick Sort in JavaScript #
function quickSort(arr) {
if (arr.length <= 1) return arr;
const [pivot, ...rest] = arr;
const left = rest.filter((x) => x < pivot);
const right = rest.filter((x) => x >= pivot);
return [...quickSort(left), pivot, ...quickSort(right)];
}What algorithm does Array.prototype.sort use? #
The specification does not name an algorithm, so this is an engine-by-engine question — but since 2018 the answer has converged.
V8 (Chrome, Node.js, Edge) uses Tim Sort. V8 switched in version 7.0, shipping with Chrome 70. Before that it used Insertion Sort for arrays of 10 or fewer elements and Quick Sort above that — which was unstable, so equal elements could be reordered unpredictably depending on array length. SpiderMonkey (Firefox) uses Merge Sort, and JavaScriptCore (Safari) also uses a stable merge-based sort.
Crucially, this is no longer left to chance. ES2019 made stability a specification requirement, so every compliant modern engine must preserve the relative order of equal elements. Code that relied on the old unstable behaviour was already broken; code that assumes stability is now safe.
The numeric gotcha you must know #
This is the single most common JavaScript sorting bug, and it is not a bug in the engine:
[1, 10, 9, 2].sort();
// → [1, 10, 2, 9] ...not what you wanted
With no comparator, sort() converts every element to a string and compares those strings by UTF-16 code unit. As text, "10" really does come before "9", exactly as "apple" comes before "banana". The array is correctly sorted — just not numerically.
The fix is to always pass a comparator when sorting numbers:
[1, 10, 9, 2].sort((a, b) => a - b);
// → [1, 2, 9, 10]
Two related traps. sort() mutates the array in place and returns the same reference, so it does not give you a sorted copy — use toSorted() in modern runtimes, or [...arr].sort(), if you need the original preserved. And undefined values are always moved to the end regardless of your comparator, without ever being passed to it.
Frequently asked questions
What algorithm does JavaScript Array.sort() use? +
Why does JavaScript sort numbers incorrectly? +
Is JavaScript's Array.sort stable? +
What algorithm does V8 use for sorting? +
Why does sort() put 10 before 9? +
See it in motion
Watch this algorithm and nine others run step by step, with live pseudocode and comparison counters.
Launch the visualiser
Software engineer at a stealth-stage startup, and previously a front-end engineer for around a year and a half.