Array.prototype.sort()
Two traps in one method: it mutates the array you gave it, and without a comparator it sorts numbers as strings. Both are visible in the demo below.
Demo
Look at the first case: [10, 9, 1] sorts to [1, 10, 9], not [1, 9, 10]. Without a comparator every element is converted to a STRING first, and "10" sorts before "9" because the character 1 comes before 9. Now look at the last two number cases — [1, 10, 2] and [100, 25, 3] come back completely UNCHANGED, because they were already in string order. And the single-digit case sorts perfectly, because for one digit string order and numeric order agree. That is why this bug survives testing so reliably: it is invisible on small numbers and silent on the rest. Pass (a, b) => a - b whenever the elements are numbers.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| compareFn | Function | no (string comparison) | Called as compareFn(a, b). Return a negative number to place a first, positive to place b first, 0 to treat them as equal. Omitted, elements are converted to strings and compared by UTF-16 code unit. |
Return value
Array — The SAME array, sorted in place. The return value is a reference to the original, not a copy.
Common patterns
items.sort((a, b) => a - b);
const sorted = [...items].sort((a, b) => a - b); const sorted2 = items.toSorted((a, b) => a - b); // ES2023
users.sort((a, b) => a.name.localeCompare(b.name));
Examples
Pitfalls
[10, 9, 1].sort()
[10, 9, 1].sort((a, b) => a - b)
const a = [3, 1]; const b = a.sort(); a
const b = [...a].sort();
[3, 1, 2].sort((a, b) => a > b)
[3, 1, 2].sort((a, b) => a - b)
['b', 'a'].sort((a, b) => a - b)
['b', 'a'].sort((a, b) => a.localeCompare(b))
When to use
- Ordering an array you own and are happy to mutate
- Any sort where you can supply an explicit comparator
- Sorting objects by a field with localeCompare or subtraction
- The array is shared or a prop → copy first, or use toSorted
- You have not written a comparator and the elements are numbers
- You need a stable numeric sort of mixed types → normalise first
Notes
FAQ
Because the default comparator converts every element to a string and compares UTF-16 code units. "10" begins with the character 1, which sorts before 9, so 10 lands before 9. Pass (a, b) => a - b for numbers.
[10, 9, 1].sort((a, b) => a - b) // [1, 9, 10]