为什么 {} > [] ?

2025-06-08

为什么 {} > [] ?

TLDR 版本

关系比较

在 JavaScript 中,关系比较的结果由抽象关系比较算法确定。该算法将比较的两边都转换为原始值,然后返回这两个原始值的比较结果。

ToPrimitive¹

抽象关系比较算法调用ToPrimitive两次,每个操作数一次,并将“number”作为第二个参数传递。这告诉函数ToPrimitive,如果操作数可以转换为多个基本类型,并且 number 是其中之一,则应该将值转换为数字,而不是其他类型。

普通到原始²

如果传递的值ToPrimitive是一个对象,则它会OrdinaryToPrimitive使用相同的两个参数(值和类型提示)进行调用。OrdinaryToPrimitive生成一个方法列表,用于调用将值转换为原始值。

如果传入的是“string”作为类型提示,则方法顺序将变为toString后跟valueOf。在本例中,由于传入的是“number”,因此方法顺序将变为valueOf后跟toString。需要注意的是,虽然到达此处的所有值都是对象,但并非每个值都会使用Object原型上的valueOf和方法toString

如果第一个方法返回“object”类型的值,则返回第二个方法的调用结果。如果第一个方法没有返回“object”类型的值,则返回第一个方法的调用结果。

普通转原始({})

对于 {} 的情况,唯一被检查的原型是Object,因此它首先尝试使用³调用valueOf对象,但返回的是 {}。由于 typeof {} === "object",它转到下一个方法。然后调用 ;如果对一个对象值调用 ,则将内置标签设置为 "Object"。 的返回值是 [object ", tag, "] 的串联。因此,传入空对象的返回值为 [object Object]"Object.prototype.value()Object.prototype.toString()
Object.prototype.toString()Object.prototype.toString()

普通转原始( [] )

对于 [] 的情况,需要考虑两个原型—— Array Object 。如果Array原型上存在某个方法,则调用该方法。但是,如果Array 原型上不存在该方法,则会在Object原型上查找该方法。Array原型不包含 的方法valueOf,因此它首先尝试调用Object.prototype.valueOf()。这将返回 [],由于 typeof [] === "object",因此它会转到下一个方法。

Array原型确实有一个toString()方法,因此它会调用Array.prototype.toString()⁵。

Array.prototype.toString()返回数组上该方法的值join。由于数组中没有元素,因此Array.prototype.toString()空数组上的返回值为空字符串。

比较

现在双方都已转换为原始值,是时候对它们进行比较了。

"[object Object]" > ""
Enter fullscreen mode Exit fullscreen mode

任何长度的字符串的值都将大于空字符串的值。

后续行动

当一个操作数的类型为 String/Number/Symbol/BigInt 而另一个操作数是对象时,JavaScript 评估抽象相等性的方式是ToPrimitive对该对象调用相同的方法,然后检查相等性⁶。

因此,我们还可以通过执行抽象相等性检查来检查 {} 是否实际转换为"[object Object]"空字符串,以及 [] 是否转换为空字符串。

console.log({} == "[object Object]") // true
console.log([] == "") // true
Enter fullscreen mode Exit fullscreen mode

为什么浏览器中会出现 {} > [] 错误?

向提出这个问题的Martijn Imhoff致谢

JavaScript 规范的编写方式是,块语句先于表达式求值,因此,当解释器在非表达式上下文中遇到花括号时,它会将其解释为块而不是对象字面量。这就是为什么在浏览器中运行这些表达式时会报错。强制解释器将 {} 视为对象字面量而不是块的方法是将其括在括号中。

({})> [] // true;({})< [] // false;({})==

如果您打开 Node 控制台而不是浏览器控制台,您将看到:

{} > [] // true; > {} < [] // false; {} ==

这是因为 Node 做了一些改动,先将输入作为表达式求值,然后再将其作为语句求值。该改动可在此处查看。

TLDR 版本

{}转换为"[object Object]"

[]转换为""

"[object Object]" > ""


参考:

¹ ToPrimitive 规范

² OrdinaryToPrimitive 规范

³ Object.prototype.valueOf() 规范

Object.prototype.toString() 规范

Array.prototype.toString() 规范

抽象相等比较算法

鏂囩珷鏉ユ簮锛�https://dev.to/amyshackles/why-is-2hkk
PREV
A peep beneath the hood of PassportJS' OAuth flow Index
NEXT
如何避免初级开发人员常犯的错误