Sorting an array of numbers
To sort numbers in ascending order, call sort() with a compare function: arr.sort((a, b) => a - b). Without a comparator the method converts elements to strings and lines them up alphabetically, which puts 10 before 3, and that is the single most common mistake in interviews.
Theory
TL;DR
- Ascending:
arr.sort((a, b) => a - b). - Descending:
arr.sort((a, b) => b - a). - With no comparator,
sort()compares the string form of the elements. - The comparator returns a negative number, a positive number or zero, and that defines the order.
sort()mutates the source array and returns a reference to it.- Non mutating options:
[...arr].sort(cmp)orarr.toSorted(cmp)(ES2023).
Quick example
const numbers = [10, 1, 3, 20];
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 3, 10, 20]The beginner mistake: sort() with no comparator
const numbers = [10, 1, 3, 20];
numbers.sort();
console.log(numbers); // [1, 10, 20, 3], string sortingBy default sort() converts elements to strings and orders them lexicographically, character by character using UTF-16 code units. That is why "10" comes before "2": the first character "1" is smaller than "2", and the remaining digits never get looked at.
One detail worth knowing: the array itself does not become an array of strings, the numbers stay numbers. Only the comparison keys are stringified, so the console shows numbers that are simply arranged "alphabetically".
The correct way: a compare function
const numbers = [10, 1, 3, 20];
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 3, 10, 20]The (a, b) => a - b function tells the engine how to compare numbers:
- if
a - bis less than 0,agoes first; - if
a - bis greater than 0,bgoes first; - if
a - bequals 0, the order stays as it was.
| Comparator value | What it means |
|---|---|
| Negative | put a before b |
| Positive | put b before a |
| Zero | the elements are equal, the order is preserved |
Since ES2019 sort() is stable: elements for which the comparator returned zero keep their original relative order. That lets you sort in several passes, for example by name first and then by age.
Descending order and sorting without mutation
Descending order is the same comparator the other way round:
const numbers = [1, 3, 10, 20];
numbers.sort((a, b) => b - a);
console.log(numbers); // [20, 10, 3, 1]If the original array must stay intact, sort a copy:
const arr = [5, 2, 9, 1];
const sorted = [...arr].sort((a, b) => a - b);
console.log(sorted); // [1, 2, 5, 9]
console.log(arr); // [5, 2, 9, 1], the original is untouchedModern engines ship a ready made non mutating method:
const sorted = arr.toSorted((a, b) => a - b); // ES2023, returns a new arrayThis matters a lot in React and similar libraries: state.items.sort(...) changes the same object, the reference does not change, and no re-render happens.
Neighbouring cases: strings and objects
The same principle covers any data, only the comparator changes:
// numbers as strings: convert before comparing
['10', '9', '2'].sort((a, b) => Number(a) - Number(b)); // ['2', '9', '10']
// text with correct alphabetical order
['apple', 'Banana', 'cherry'].sort((a, b) => a.localeCompare(b, 'en'));
// objects by field
const users = [{ name: 'Bob', age: 31 }, { name: 'Alice', age: 25 }];
users.sort((a, b) => a.age - b.age); // Alice firstFor huge values that do not fit into Number, subtraction either returns a BigInt or loses precision, so there you write an explicit comparison:
arr.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));In brief
| Task | Code | Result |
|---|---|---|
| Ascending | arr.sort((a, b) => a - b) | [1, 2, 3, 4] |
| Descending | arr.sort((a, b) => b - a) | [4, 3, 2, 1] |
| Without changing the source array | [...arr].sort(...) | a new sorted array |
| Without changing it, modern syntax | arr.toSorted(...) | a new sorted array |
Summary: to sort numbers in ascending order, always pass a compare function:
arr.sort((a, b) => a - b).
Common mistakes
- Calling
sort()with no arguments on numbers. That is lexicographic sorting, and on any array mixing one digit and two digit numbers the result is almost always wrong. - Returning
trueorfalsefrom the comparator. For examplearr.sort((a, b) => a > b): a boolean coerces to 1 or 0, the engine never receives "less than", and the order becomes unpredictable. A comparator must return a signed number. - Forgetting that
sort()mutates. It changes the source array and returns that same array, not a copy. For data you do not own, props and state, copy first. - Sorting an array that contains
NaN. Any subtraction withNaNyieldsNaN, so the comparator effectively answers "unknown" and the order becomes garbage. Filter such values out beforehand. - Ignoring
undefinedand holes.undefinedvalues always end up at the end, empty slots of a sparse array go even further, and the comparator is never called for them. - Comparing text with
a - bora > b. For strings with non ASCII letters, the correct order comes fromlocaleComparewith the right locale.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.