There is no concept of a typed number array in JS. There is just "Array", and an array's contents can be heterogenous.
Imagine the following:
['a', 'c', 'b'].sort() // ['a','b','c']
['a', 1].sort() // [1, 'a']
[1, ['foo'], {bar: 'baz'}, 'a', '2', null, undefined].sort() // [1, '2', {bar:'baz'}, 'a', ['foo'], null, undefined]
The default comparator is one that can be run on any arbitrary array. It's up to you as a caller to specify that you'd like to sort by a different comparator.For a more detailed read, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Note that nowadays there are indeed Int16Array, Float32Array, and so forth, and their sort methods work numerically like you'd expect.
Is there an explanation somewhere of how they decided on that as the default comparator? My first inclination would have been to use "<" as the default comparator. That would sort purely numeric arrays numerically, and purely string arrays lexically, leaving only the case of arrays that mix numerical and non-numerical elements needing the programmer to step in and give an explicit comparator.
It's JavaScript … it doesn't have to be sane; we'll use it anyway.
I think that Erlang had the most elegant solution: it defines a total order over all objects (number < atom < reference < fun < port < pid < tuple < list < bit string). Of course, Erlang's 'strings' are pretty inelegant (they're just lists of integers, which are printed as strings if they happen to incidentally be valid characters), so I guess there's some Law of Conservation of Bogosity at play here.
It may seem like a strange way to spec the language, but I'm not sure what would have been better. It wouldn't make sense for sort to have to run through the array checking types before it starts, or for it to dynamically change what kind of comparison it does depending on the types of each pair of elements being compared.
arr1.sort( Array.NUMERICAL | Array.DESCENDING )
arr2.sort( Array.CASE_INSENSITIVE )
or similar.E.g.:
[1,3,NaN,2,5].sort( (a,b) => a<b ? -1 : 1 )
// Chrome: [ NaN, 1, 2, 3, 5 ]
// Firefox: [ 2, 5, NaN, 1, 3 ]In (almost) every other language ever the following is true. In Javascript it is false.
[2] < [11]
This means:[[2], [11]].sort() // Javascript: [ [11], [2] ]
As for the actual behavior of ([2] < [11]), the issue there is that "Array" is not a type in JS, arrays are just objects that happen to have properties called "0" and "1" and so on. Hence operators don't have any special cases for arrays, so getting comparisons to work like you had hoped would mean the comparison operator would need weird special rules where, whenever it's passed two objects it checks if they both have properties called "0", and if so do one thing, if not do something else, etc.
What is the correct order of the items ["2", 10, "banana", [[]], "", 1]?
See also https://www.destroyallsoftware.com/talks/wat
Bonus: sometimes you can get the same kind of behaviour in Excel when importing CSV.
It is trickier when someone compares "2" and 3, should we say it's invalid (my preference) or turn 2 into an integer, or 3 into a string? However, there is NO reason for there to be an issue comparing 1 and 11. This is just an unfortunately mistake that is too deeply baked into the language to fix at this point.
> [2] < [11]
false
Technically, a combination of integers and arrays. Still took me an afternoon to track down (it didn't occur to me javascript would work like that).Obviously it's too late to change JavaScript now, but Iwould be interested to know why it would have been complicated to do this differently originally, and why it would be countintuitive? Is there anything I can read about this kind of thing?
I guess "Javascript: the Good Parts" is as good a place to start as any. It doesn't really go into the design decisions though.