在这个 2 个空数组的松散相等比较中发生了什么

What is happening in this loose equality comparison of 2 empty arrays

我很难理解这段代码在基本层面上的工作原理

if([] == ![]){
console.log("this evaluates to true");
}

请帮助我了解我哪里错了。我的想法:

  1. 首先是运算符优先级,因此 !== 之前计算。
  2. 接下来调用 ToPrimitive 并且 [] 转换为空字符串。
  3. ! 运算符注意到它需要将 "" 转换为 boolean 因此它采用该值并将其转换为 false 然后取反为 true .
  4. == 更喜欢比较数字所以在我看来 true 使 1[] 转换为 "" 然后 0

为什么它会起作用?我哪里弄错了?

Why does it work then?

TLDR:

[] == ![]
        //toBoolean [1]
[] == !true
[] == false
//loose equality round one [2]
//toPrimitive([]); toNumber(false) [3]
"" == 0
//loose equality round two
//toNumber("") [4]
0 === 0
true

一些解释:

1)

First there is operator precedence so ! evaluates before ==

Negating something calls the internal toBoolean 方法首先应用于 "something"。在这种情况下,这是一个对象(因为数组是对象)并且它总是 returns true 然后被否定。

2)

现在是 loose equalities special behaviour(有关更多信息,请参阅 Taurus 的回答):

If A is an Object ( Arrays are Objects ) and B is a Boolean it will do:

ToPrimitive(A) == ToNumber(B)

3)

  toPrimitive([])

ToPrimitive(A) attempts to convert its Object argument to a primitive value, by attempting to invoke varying sequences of A.toString and A.valueOf methods on A.

通过调用 toString(因为它们没有 valueOf 方法)将数组转换为其原语,这基本上是 join(",").

toNumber(false)

The result is 1 if the argument is true. The result is +0 if the argument is false. Reference

所以false转换为+0

4)

toNumber("")

A StringNumericLiteral that is empty or contains only white space is converted to +0.

所以最后""转换为+0

Where did I get it wrong?

在第 1 步。否定某事不会调用 toPrimitivetoBoolean ...

首先,意识到您正在比较两种不同类型的值。 当您使用 ![] 时,结果为 false。你有代码(核心结果是这样的):

if([] == false)

现在是第二部分:由于两个值的类型不同并且您使用的是“==”,javascript 将两个值类型都转换为字符串(以确保它们具有相同的类型)。它从左边开始。 在左边我们有 []。因此 javascript 在 [] 上应用 toString 函数,结果为 false。尝试 console.log([].toString())

你应该在左边得到 false 作为字符串值。在右边我们有布尔值 false,javascript 做同样的事情。 它还在 false 上使用 toString 函数,这导致字符串值为 false。 尝试 console.log(false.toString())

这涉及两个核心概念:“==”的工作原理和“==”运算符的结合性——无论是从左开始还是从右开始。

关联性是指调用运算符函数的方式:从左到右或从右到左。 == 或 ! 等运算符或 + 是使用前缀表示法的函数! 如果您使用“===”,上述 if 语句将导致错误。 希望对您有所帮助。

接受的答案不正确(不过现在是),请看这个例子:

if([5] == true) {
console.log("hello"); 
}

如果确实按照接受的答案状态处理所有内容,那么 [5] == true 应该评估为 true,因为数组 [5] 将被转换为其对应的字符串("5"),并且字符串 "5" 为真(Boolean("5") === truetrue),因此 true == true 必须为真。

但这显然不是这种情况,因为条件不计算为 true

所以,实际情况是:

1. ![] 会将其操作数转换为布尔值,然后翻转该布尔值,每个对象都是真实的,因此 ![] 将计算为 false.

此时比较就变成了[] == false


2. 然后发挥作用的是这 2 条规则,clearly stated 在抽象平等比较算法规范的#6 中:

  1. If Type(x) is boolean, return the result of the comparison ToNumber(x) == y.
  2. If Type(y) is boolean, return the result of the comparison x == ToNumber(y)

此时比较就变成了[] == 0.


3. 那么就是这个规则:

If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.

如@Jonas_W所述,数组的 ToPrimitive 将调用其 toString,这将 return 以逗号分隔的内容列表(我过于简单化了) .

此时比较就变成了"" == 0.


4. 最后(好吧,差不多)这条规则:

If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.

空字符串转换为数字是0Number("") == 0true)。

此时比较就变成了0 == 0.


5.最后,这条规则将适用:

If Type(x) is the same as Type(y), then
.........
  If Type(x) is Number, then
.........
    If x is the same Number value as y, return true.


而且,这就是比较结果为 true 的原因。您还可以将这些规则应用到我的第一个示例中,看看为什么它的计算结果不是 true


我上面引用的所有规则都在规范中明确说明here