To understand the results of your test cases, you need to understand what happens when you compare arrays or any other object using any relational operator.
Long story short, objects are converted to strings before they are compared using any of the relational operator.
(skip to the end of the answer if you don't want to read about object-to-primitive conversion.)
ToPrimitive abstract operation
To convert objects to primitive values, javascript performs toPrimitive abstract operation that takes two arguments:
input
: object that should be converted to a primitive value
preferredType
: optional second argument that specifies the type that should be favoured when converting an object to a primitive value
For object to primitive conversion, toPrimitive abstract operation invokes another abstract operation known as OrdinaryToPrimitive
OrdinaryToPrimitive abstract operation
For object to primitive conversion, toPrimitive abstract operation invokes OrdinaryToPrimitive
abstract operation with two arguments:
O
: object that should be converted to a primitive value
hint
: type that should be favored when converting the object to a primitive value
toPrimitive abstract operation sets the hint
as following:
- If the
preferredType
is a string
, set hint
to string
- If the
preferredType
is a number
, set hint
to number
- If
preferredType
is not specified, set hint
to number
OrdinaryToPrimitive abstract operation uses following three algorithms to convert the object to a primitive value:
prefer-string: If hint
is string
, return a primitive value, preferring a string value, if conversion to string is possible
prefer-number: If hint
is number
, return a primitive value, preferring a number value, if conversion to number is possible
no-preference: This algorithm expresses no preference about what type of primitive value should be returned and lets the objects define what type of primitive value should be returned. If hint
is default
or there is no hint
, this algorithm is used to convert an object to a primitive value.
It allows objects to override the default ToPrimitive
behavior. Among the built-in objects, only Date
and Symbol
objects override the default ToPrimitive
behavior. Date
and Symbol
objects implement this algorithm as prefer-string
whereas all the other built-in objects implement this algorithm as prefer-number
(Objects can override the default ToPrimitive
behavior by implementing Symbol.toPrimitive method.)
All objects inherit two methods that are used to convert objects to primitive values. These two methods are:
object to primitive conversion involves calling above mentioned methods and the object to primitive conversion algorithms mentioned above, call these two methods in different order.
prefer-string
This algorithm first calls the .toString()
method and if the resulting value is a primitive value, javascript uses the returned primitive value, even if it's not a string.
If the .toString()
method doesn't exists or it returns an object
, then .valueOf()
method is called. If .valueOf()
method returns a primitive value, then that value is used otherwise TypeError
is thrown.
prefer-number
Only difference between this algorithm and prefer-string
is that it first invokes .valueOf()
method and then .toString()
method.
no-preference
When there is no preferred type or hint or if the preferred type is default
, by default, prefer-number
algorithm is used.
Objects can override this behaviour and of all the built-in objects, only Date
and Symbol
override this default ToPrimitive
conversion behaviour. Date
and Symbol
use prefer-string
algorithm when there is no preferred type or a hint or the preferred type is default.
Now coming back to you question, relational operators, i.e. <, >=, <, <=
can be used to compare strings as well as numbers. If either operand of these operators is an object
, it is converted to primitive value using prefer-number
algorithm. So when you compare two arrays using a relational operator, javascript tries to convert each array into a primitive value using prefer-number
algorithm.
As mentioned above, prefer-number
algorithm first calls .valueOf()
method. If return value is a primitive value, that value is used, otherwise .toString()
method is called.
Default implementation of .valueOf()
method simply returns the object itself rather than returning a primitive value, so javascript always ends up calling .toString()
method when it uses prefer-number
algorithm.
When .toValue()
method is called on an array, it simply returns the array on which this method was called. Javascript then calls .toString()
method on this returned array. When .toString()
method is called on an array, it converts all the elements of the array into strings and then joins all the strings together with commas in between each string.
So when you compare [1] > [2]
, you are comparing '1' > '2'
and similarly [1,2] > [1,1]
is converted to '1,2' > '1,1'
.
As strings are compared by their unicode code points, '1' > '2'
evaluates to false
and '1,2' > '1,1'
evaluates to true
.