Behavior of "Greater than" (and another inequality comparison operators) on arrays

Som*_*ceS 5 javascript arrays comparison

I couldn't find any description or any mention about how >, <, <= and >= operators behave while comparing two arrays in javascript.

The only trivial thing I could think of is that the two arrays are compared by both elements for each relative indexes, but after testing it - I didn't got the result I expected.

So how arrays are being compared?

Few test cases:

console.log([1] > [2]); // FALSE - ok
console.log([2] > [1]); // TRUE - ok
console.log([2] > [2]); // FALSE - ok
console.log([1,2] > [2,3]); // FALSE - In case two elements in each index are compared, and the answer is "If all >" - ok  
console.log([2,2] > [1,1]); // TRUE - In case two elements in each index are compared, and the answer is "If all >" - ok
console.log([1,2] > [1,1]); // TRUE - In case two elements in each index are compared, and the answer is "If all >" - Unexpected
// More cases with 3 elements:
console.log([1,2,1] > [1,2,2]); // FALSE
console.log([1,1,1] > [1,1,2]); // FALSE
console.log([1,3,1] > [1,3,0]); // TRUE
console.log([1,1,1] > [1,1,2]); // FALSE
Run Code Online (Sandbox Code Playgroud)

You*_*saf 4

要了解测试用例的结果,您需要了解使用任何关系运算符比较数组或任何其他对象时会发生什么。

长话短说,对象在使用任何关系运算符进行比较之前会先转换为字符串

如果您不想阅读有关对象到基元转换的内容,请跳到答案的末尾。)

ToPrimitive抽象操作

为了将对象转换为原始值,JavaScript 执行带有两个参数的toPrimitive抽象操作:

  • input:应转换为原始值的对象
  • preferredType:可选的第二个参数,指定将对象转换为原始值时应优先使用的类型

对于对象到基元的转换,toPrimitive抽象操作调用另一个称为OrdinaryToPrimitive 的抽象操作

OrdinaryToPrimitive 抽象操作

对于对象到基元的转换,toPrimitive抽象操作OrdinaryToPrimitive使用两个参数调用抽象操作:

  • O:应转换为原始值的对象
  • hint:将对象转换为原始值时应优先选择的类型

toPrimitive抽象操作设置hint如下:

  • 如果preferredType是 a string,则设置hintstring
  • 如果preferredType是 a number,则设置hintnumber
  • 如果preferredType未指定,则设置hintnumber

OrdinaryToPrimitive抽象操作使用以下三种算法将对象转换为原始值:

  • Preferred-string:如果hintstring,则返回一个原始值,如果可以转换为字符串,则首选字符串值

  • Preferred-number:如果hintnumber,则返回一个原始值,如果可以转换为数字,则首选数字值

  • 无偏好:此算法不表达应返回什么类型的原始值的偏好,并让对象定义应返回什么类型的原始值。如果hintdefault或没有hint,则使用此算法将对象转换为原始值。

    它允许对象覆盖默认ToPrimitive行为。在内置对象中,只有DateSymbol对象会覆盖默认ToPrimitive行为。Date并且Symbol对象实现此算法,prefer-string而所有其他内置对象实现此算法为prefer-number(对象可以通过实现Symbol.toPrimitive方法来覆盖默认ToPrimitive行为。)

所有对象都继承两个用于将对象转换为原始值的方法。这两种方法是:

  • .valueOf()
  • .toString()

对象到原始数据的转换涉及到调用上面提到的方法和上面提到的对象到原始数据转换算法,这两个方法的调用顺序不同。

首选字符串

该算法首先调用该.toString()方法,如果结果值是原始值,则 javascript 使用返回的原始值,即使它不是字符串。

如果该.toString()方法不存在或者返回一个object,则.valueOf()调用该方法。如果.valueOf()方法返回原始值,则使用该值,否则TypeError抛出异常。

首选号码

该算法与 的唯一区别prefer-string在于它首先调用.valueOf()方法,然后.toString()调用方法。

没有偏好

当没有首选类型提示或者首选类型为时default,默认情况下prefer-number使用算法。

对象可以覆盖此行为以及所有内置对象,Date并且只能Symbol覆盖此默认ToPrimitive转换行为。Date并在没有首选类型提示首选类型Symbol为默认类型时使用算法。prefer-string


现在回到你的问题,关系运算符,即<, >=, <, <=可以用来比较字符串和数字。如果这些运算符的任一操作数是object,则使用算法将其转换为原始值prefer-number。因此,当您使用关系运算符比较两个数组时,JavaScript 会尝试使用算法将每个数组转换为原始值prefer-number

如上所述,prefer-number算法首先调用.valueOf()方法。如果返回值是原始值,则使用该值,否则.toString()调用方法。

方法的默认实现.valueOf()只是返回对象本身而不是返回原始值,因此javascript.toString()在使用prefer-number算法时总是最终调用方法。

.toValue()对数组调用方法时,它只是返回调用该方法的数组。然后 JavaScript.toString()对该返回的数组调用方法。当.toString()对数组调用方法时,它将数组的所有元素转换为字符串,然后将所有字符串连接在一起,每个字符串之间用逗号分隔。

因此,当您比较时[1] > [2],您正在比较'1' > '2'并且类似地[1,2] > [1,1]转换为'1,2' > '1,1'

当字符串按其 unicode 代码点进行比较时,'1' > '2'计算结果为false和。'1,2' > '1,1'true