Why JavaScript Sorts Numbers as Strings (and the Fix)
JavaScript's default Array.sort() converts elements to strings, so [100, 25, 9] sorts to [100, 25, 9] wrong - '100' < '25' as text. The fix is a compare function. Here's why it happens and the one-liner that fixes it.
The bug
[100, 25, 9].sort(); // -> [100, 25, 9] (WRONG)
[9, 50, 25].sort(); // -> [25, 50, 9] (WRONG)
A leaderboard where 9 outranks 50 is this exact bug.
Why it happens
Called with no argument, Array.prototype.sort() converts every element to a string and
sorts lexicographically (like dictionary order). As strings, "100" comes before "25"
because "1" < "2", and "25" comes before "9" because "2" < "9". The numbers are
never compared as numbers.
The fix: a compare function
Pass a comparator. It returns a negative number if a should come first, positive if b
should, zero if equal - and a - b does exactly that for numbers:
[100, 25, 9].sort((a, b) => a - b); // ascending -> [9, 25, 100]
[9, 50, 25].sort((a, b) => b - a); // descending -> [50, 25, 9] (leaderboard)
(a, b) => a - b-> ascending(a, b) => b - a-> descending
The details that bite
sort()mutates the array in place. To keep the original, copy first:[...scores].sort((a, b) => b - a).- Don't
return a > b- a comparator must return a number, not a boolean;truecoerces to 1 and the sort is subtly wrong. - Sorting objects: compare the field -
items.sort((a, b) => b.score - a.score). - Strings sort fine without a comparator (that's the default) - the comparator is only
needed for numbers (and locale-aware text via
localeCompare).
Sorting objects, strings, and stability
The compare-function rule extends past plain numbers. To sort objects, return the difference of the field you care about: users.sort((a, b) => a.age - b.age). For strings, subtraction does not work - use a.localeCompare(b), which also handles accents and locale order (and b.localeCompare(a) to reverse).
Two gotchas worth knowing:
sort()mutates in place and returns the same array. If you need to keep the original - common in React, where mutating state breaks rendering - copy first:[...arr].sort(...).- Stability: modern engines guarantee a stable sort, so equal elements keep their original order. That lets you sort by one key, then another, for multi-level ordering.
For descending numbers use (a, b) => b - a; for nullable values, normalize them in the comparator so undefined doesn't sort randomly.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Writing an ascending/descending numeric comparator
- Copying before sort to avoid mutating the source
- Sorting objects by a numeric field
FAQ
Why does JavaScript sort numbers in the wrong order?
Array.sort() with no argument converts elements to strings and sorts them lexicographically, so '100' comes before '25'. Pass a compare function like (a, b) => a - b to sort numerically.
How do I sort an array of numbers in JavaScript?
Use a comparator: arr.sort((a, b) => a - b) for ascending, arr.sort((a, b) => b - a) for descending. Copy first with [...arr] if you don't want to mutate the original.
How do I sort an array of objects by a number field?
Subtract the fields in the comparator: items.sort((a, b) => b.score - a.score) sorts by score descending.
How do you sort numbers in JavaScript?
Pass a compare function to sort: arr.sort((a, b) => a - b) for ascending, (a, b) => b - a for descending. Without it, sort() converts elements to strings, so 100 sorts before 25.
Does sort() work with numbers by default?
No. Array.sort() with no argument sorts lexicographically (as strings), so [25, 100] becomes [100, 25]. You must pass a numeric compare function.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →