我试图找出为什么JavaScript在比较同一个数组时有这种奇怪的行为:
var array = [0];
console.log(array == array); //true
console.log(array == !array); //true?
第一个很容易完成,它们引用相同的对象,但第二个是非常棘手的,我正在努力理解这个过程。
请注意,我知道这是abstract equality
比较,而不是strict equality
比较,我知道他们的差异(我知道使用===
会导致{{1} }结果,但我试图找出false
)的行为。
P.s。:这个是从wtfjs.com中取出的,我没有找到解释,所以我试着自己给它并认为它可能是“有用的”。
答案 0 :(得分:2)
第一个相等很简单,它是同一个对象(同一个引用)之间的比较,因此返回true
。
第二个有点棘手,所以我试着在下面解释一下。
对于那些有点懒惰的人来说,这是一个简单的解释,而不是每一步都引用规范:
[0] == ![0]
=>我们首先评估![0]
,这会产生false
(因为[0]
是 truthy 值)。
[0] == false
=> [0]
评估为[0].toString()
,"0"
。
"0" == false
=> "0"
转换为0
;同样适用于false
,因此我们获得:
0 == 0
,最后是true
。
至于第一个相等,为了完整起见,我引用了规范中感兴趣的部分。
1.f如果x和y引用同一个对象,则返回true。否则,返回false。
所以这会像预期的那样返回true。现在是棘手的部分:
首先,我们必须评估右侧的UnaryExpression
:
但是 ToBoolean 使用此algorithm, GetValue 应该返回Object
或非空String
,所以评估结果为 true
。返回我们的UnaryExpression
,我们有!true
,因此最终评估的结果为false
。
所以我们回到原始比较中,现在我们将Object
与Boolean
进行比较。
7.如果Type(y)是布尔值,则返回比较结果x == ToNumber(y)。
ToNumber(false)
为0
,现在我们正在比较Object
和Number
。
返回规格:
9.如果Type(x)是Object而Type(y)是String或Number,则返回比较结果ToPrimitive(x)== y。
在我们的数组上调用ToPrimitive
应返回其[[DefaultValue]]
,根据this kangax's answer,应该是在数组本身上调用toString
的结果,因此我们获得"0"
。
因此,回到我们的比较,它已成为String
和Number
之间的平等。
5.如果Type(x)是String而Type(y)是Number,则返回比较结果ToNumber(x)== y。
在我们的字符串"0"
上调用ToNumber
会产生0
,我们再次进行简单的比较:0 == 0
。
最终规范步骤:
1.c.iii如果x与y的数值相同,则返回true。
这里结果解释了。
答案 1 :(得分:0)
algorithm for the ==
operator从左到右评估表达式,所以给出:
var array = [0];
并评估:
array == !array;
然后首先评估左手表达式并返回一个数组。然后评估右手表达式:ToBoolean应用于数组,因为它是一个对象,它返回 true 和{{1 }}运算符将其反转为 false 。
然后使用abstract equailty comparison algorithm。同样,首先评估左侧。由于 array 是一个Object而不是Boolean,String或Number,因此使用了第7步,右侧转换为Number,比较变为:
!
算法再次运行并进入步骤9,其中 array 被转换为原语(在本例中为字符串),比较变为:
array == 0;
算法再次运行并进入步骤5,左侧转换为数字,比较变为:
'0' == 0;
算法再次运行,这次表达式具有相同的Type(Number),因此步骤1.iii.c用于返回 true 。
请注意,通过所有这些,始终首先评估左侧,但有时会导致右侧被修改而不是左侧(例如,在算法的第7步)。