在这个 2 个空数组的松散相等比较中发生了什么
What is happening in this loose equality comparison of 2 empty arrays
我很难理解这段代码在基本层面上的工作原理
if([] == ![]){
console.log("this evaluates to true");
}
请帮助我了解我哪里错了。我的想法:
- 首先是运算符优先级,因此
!
在 ==
之前计算。
- 接下来调用
ToPrimitive
并且 []
转换为空字符串。
!
运算符注意到它需要将 ""
转换为 boolean
因此它采用该值并将其转换为 false
然后取反为 true
.
==
更喜欢比较数字所以在我看来 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 步。否定某事不会调用 toPrimitive
但 toBoolean
...
首先,意识到您正在比较两种不同类型的值。
当您使用 ![] 时,结果为 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") === true
为 true
),因此 true == true
必须为真。
但这显然不是这种情况,因为条件不计算为 true
。
所以,实际情况是:
1. ![]
会将其操作数转换为布尔值,然后翻转该布尔值,每个对象都是真实的,因此 ![]
将计算为 false
.
此时比较就变成了[] == false
2. 然后发挥作用的是这 2 条规则,clearly stated 在抽象平等比较算法规范的#6 中:
- If Type(x) is boolean, return the result of the comparison ToNumber(x) == y.
- 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.
空字符串转换为数字是0
(Number("") == 0
是true
)。
此时比较就变成了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。
我很难理解这段代码在基本层面上的工作原理
if([] == ![]){
console.log("this evaluates to true");
}
请帮助我了解我哪里错了。我的想法:
- 首先是运算符优先级,因此
!
在==
之前计算。 - 接下来调用
ToPrimitive
并且[]
转换为空字符串。 !
运算符注意到它需要将""
转换为boolean
因此它采用该值并将其转换为false
然后取反为true
.==
更喜欢比较数字所以在我看来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 步。否定某事不会调用 toPrimitive
但 toBoolean
...
首先,意识到您正在比较两种不同类型的值。 当您使用 ![] 时,结果为 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") === true
为 true
),因此 true == true
必须为真。
但这显然不是这种情况,因为条件不计算为 true
。
所以,实际情况是:
1. ![]
会将其操作数转换为布尔值,然后翻转该布尔值,每个对象都是真实的,因此 ![]
将计算为 false
.
此时比较就变成了[] == false
2. 然后发挥作用的是这 2 条规则,clearly stated 在抽象平等比较算法规范的#6 中:
- If Type(x) is boolean, return the result of the comparison ToNumber(x) == y.
- 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.
空字符串转换为数字是0
(Number("") == 0
是true
)。
此时比较就变成了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。