When neither the function nor the parameters have hard types, you have to create heuristics. There could be a test for numbers there, but it would also be surprising because at the older days people expected "10" and 10 to behave the same.
[1, 10, 2].sort((a,b) => a > b ? 1 : -1)
// -> [1, 2, 10]
is something like // [1, 10, 2].sort((a,b) => a.toString() > b.toString() ? 1 : -1)
// -> [1, 10, 2]
because someone thought that it was "best" to cast stuff to string in case whatever you put in the container didn't implement comparison.A JavaScript sort comparator is required to not only return a positive or negative value, it must handle all three cases: greater than, less than, or equal. When the arguments compare equal, the comparator must return 0.
Returning only a positive or negative value is a very common error. (I don't mean to pick on you for this! I have seen the error so often that I hope this may be helpful for anyone writing a sort comparator.)
The invalid comparator will force the normally stable sort to be unstable, because sort() now has no way to know that two items should be considered equal and their existing order preserved.
Let's demonstrate with the "doggos" example that the article links to:
https://mathiasbynens.be/demo/sort-stability
The code starts with this array:
const doggos = [
{ name: 'Choco', rating: 12 },
{ name: 'Devlin', rating: 13 },
{ name: 'Eagle', rating: 13 },
{ name: 'Jenny', rating: 13 },
{ name: 'Kona', rating: 13 },
{ name: 'Leila', rating: 13 },
{ name: 'Milly', rating: 14 },
{ name: 'Molly', rating: 12 },
{ name: 'Nova', rating: 12 },
{ name: 'Oliver', rating: 13 },
{ name: 'Patches', rating: 14 },
];
It uses this valid comparator: doggos.sort( ( a, b ) => b.rating - a.rating );
(Note that this implements a reverse sort as can be seen in the output on the test page.)Subtraction provides the proper return values when two numbers are compared: any negative number, any positive number, or zero when the ratings are equal.
Another valid comparator (again using a reverse sort) would be:
doggos.sort( ( a, b ) =>
a.rating < b.rating ? 1 :
a.rating > b.rating ? -1 :
0
);
Either way you get the expected output in the current version of Chrome, which has a stable sort. Each group of doggos with the same rating appear in their original order: [
{ name: "Milly", rating: 14 },
{ name: "Patches", rating: 14 },
{ name: "Devlin", rating: 13 },
{ name: "Eagle", rating: 13 },
{ name: "Jenny", rating: 13 },
{ name: "Kona", rating: 13 },
{ name: "Leila", rating: 13 },
{ name: "Oliver", rating: 13 },
{ name: "Choco", rating: 12 },
{ name: "Molly", rating: 12 },
{ name: "Nova", rating: 12 }
]
So let's go back to the original doggos array and use a sort function that only returns 1 or -1 (once again using a reverse sort): doggos.sort( ( a, b ) =>
a.rating < b.rating ? 1 : -1
);
With this function, the result is: [
{ "name": "Patches", "rating": 14 },
{ "name": "Milly", "rating": 14 },
{ "name": "Oliver", "rating": 13 },
{ "name": "Leila", "rating": 13 },
{ "name": "Kona", "rating": 13 },
{ "name": "Jenny", "rating": 13 },
{ "name": "Eagle", "rating": 13 },
{ "name": "Devlin", "rating": 13 },
{ "name": "Nova", "rating": 12 },
{ "name": "Molly", "rating": 12 },
{ "name": "Choco", "rating": 12 }
]
Now the sort has become unstable. Doggos with the same rating are no longer in their original order.Bottom line, be sure to handle all three cases in your sort comparator if you want a stable sort.