Sorting
The last worker at our conveyor is a sorter. The sorter takes two boxes, compares them and decides which one goes first. Pair by pair, the sorter puts the whole belt in order.
The sort method is such a sorter: it puts the elements of an array in order. With words it works as expected, but with numbers it does not:
const words = ["pear", "apple", "fig"];
words.sort();
console.log(words); // [ 'apple', 'fig', 'pear' ]
const nums = [25, 100, 3];
nums.sort();
console.log(nums); // [ 100, 25, 3 ]Let's see what happened:
- The words are in alphabetical order:
apple,fig,pear. - The numbers are in a strange order:
100comes first, although it is the largest.
Interviewers often ask why this happens with numbers. The answer lies in how sort compares elements without a hint.
Comparing as strings
Without an argument, sort converts each element to a string and compares the strings character by character, like words in a dictionary. The string "100" starts with "1", and "1" is less than "2" and "3". That is why 100 comes first, although as a number it is the largest.
The string "10" is also less than the string "9": "10" < "9" gives true. Strings are compared by character codes, so capital letters come before lowercase ones: ["b", "A", "a"].sort() gives [ 'A', 'a', 'b' ].
A compare function
To compare numbers as numbers, the sorter gets a rule. You pass a compare function to sort. sort calls it with two elements a and b and looks at the sign of the result:
- a negative number —
agoes beforeb; - a positive number —
bgoes beforea; 0— the order of these two elements does not change.
The difference a - b is negative when a is smaller. So (a, b) => a - b sorts the numbers in ascending order, and (a, b) => b - a in descending order:
nums.sort((a, b) => a - b);
console.log(nums.join(" ")); // 3 25 100
nums.sort((a, b) => b - a);
console.log(nums.join(" ")); // 100 25 3Take the pair 25 and 3 in an ascending sort. The difference 25 - 3 is 22, a positive number, so 3 goes before 25.
Anything can be compared, for example the length of strings: words.sort((a, b) => a.length - b.length).
A compare function must return a number: negative, positive or 0. The function (a, b) => a > b returns true or false. sort reads them as 1 and 0, and never gets a negative number. With it the order can come out wrong: in Node.js [3, 1, 2] stays [3, 1, 2].
sort and toSorted
Here the sorter analogy stops working. A real sorter could put the boxes onto a new belt, but sort does not create a new array. It rearranges the elements of the array it is called on.
sort changes the array
sort changes the array in place, like push and pop. sort returns that same array, not a copy.
toSorted returns a copy
The toSorted method takes the same compare function but returns a sorted copy and leaves the original array alone. The method was added to the language in 2023; Node.js 22 and browsers released after mid-2023 know it:
const scores = [70, 95, 80];
const ranked = scores.toSorted((a, b) => b - a);
console.log(ranked.join(" ")); // 95 80 70
console.log(scores.join(" ")); // 70 95 80In ranked the scores are in descending order, and scores keeps the original order.
Common mistake
The result of sort is stored in a new constant, expecting the original array to stay as it was:
const prices = [30, 10, 20];
const sorted = prices.sort((a, b) => a - b); // ✗
console.log(prices.join(" "));There is no error, but the program prints 10 20 30: sort rearranged the elements of prices itself. sorted and prices are two names for one array, and sorted === prices gives true. When the original order is needed later, write prices.toSorted((a, b) => a - b) or sort the copy [...prices].
Key points
- Without an argument,
sortcompares elements as strings, so100comes before25. - For numbers, pass a compare function:
(a, b) => a - bfor ascending,(a, b) => b - afor descending. sortchanges the array itself and returns it, whiletoSortedreturns a new array.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.