JavaScript Array sort Without a Comparator
When you call Array.prototype.sort() in JavaScript
without providing a compare function, the method automatically converts
all non-undefined array elements into strings and sorts them in
ascending order based on their UTF-16 code unit values. This article
covers how this default string conversion works, why it causes common
bugs with numeric data, how special values like undefined
are treated, and the in-place nature of the operation.
Default String Conversion and Lexicographical Sorting
By default, the sorting algorithm treats every element as a string.
For elements that are not already strings (such as numbers, booleans, or
objects), JavaScript internally calls their .toString()
method before determining their order.
Once converted to strings, elements are compared character by character using their UTF-16 code unit values (lexicographical order).
const fruits = ['banana', 'apple', 'cherry'];
fruits.sort();
// Result: ['apple', 'banana', 'cherry']The Numeric Sorting Pitfall
Because elements are converted to strings, sorting numbers without a comparator often produces counterintuitive results. Instead of sorting by numerical value, JavaScript compares the string representations of the numbers character by character.
For example, '10' comes before '2' because
the character '1' has a lower UTF-16 code unit value than
'2':
const numbers = [10, 5, 40, 25, 1000, 1];
numbers.sort();
// Result: [1, 10, 1000, 25, 40, 5]To sort numbers by their actual mathematical value, you must supply a custom comparator function:
numbers.sort((a, b) => a - b);
// Result: [1, 5, 10, 25, 40, 1000]Handling of
undefined and Sparse Arrays
The default sorting algorithm handles undefined values
and empty slots in a specific way:
undefinedvalues: Allundefinedelements are moved to the end of the array. The internal string conversion is not called onundefined, and it is not passed through lexicographical comparison with defined values.- Sparse arrays (empty slots): Empty slots in sparse
arrays are treated as
undefinedand are also moved to the end of the array.
const mixed = [undefined, 3, , 1, 'apple'];
mixed.sort();
// Result: [1, 3, 'apple', undefined, empty]null, Booleans, and
Objects
Elements such as null, true,
false, and objects are converted to their standard string
representations prior to sorting:
nullbecomes"null"truebecomes"true"falsebecomes"false"- Plain objects generally become
"[object Object]"
const values = [null, true, false, 10];
values.sort();
// Result: [10, false, null, true]
// (Because "10" < "false" < "null" < "true")In-Place Mutation
Array.prototype.sort() mutates the original array
directly rather than returning a new copy. It also returns the reference
to the same mutated array. If you need to preserve the original array
order, create a shallow copy before sorting:
const original = [3, 1, 2];
const sorted = [...original].sort();
// original remains: [3, 1, 2]
// sorted is: [1, 2, 3]