为什么JavaScript中的[] ==! []是真的?

6
var arr = [];
Boolean(arr) // true
Boolean(!arr) // false
arr == arr // true
arr == !arr // true ??? what ???

我不想得到“建议使用 === 而不是 == ”的答案。 我想了解这种现象的原因和JavaScript类型转换的原理。

1
我认为这是因为[]是假值(尝试[] == 0),但!arr变成了!Boolean(arr),它给出了!truefalse==运算符可能不会在左侧的arr上调用Boolean(),因为它知道将空列表视为假值。 - Dillon Davis
我不能同意。空数组是“true”,而不是“false”。 - msm082919
还有一个有趣的事实:[] == [] 是错误的。 - Steve Bennett
@msm082919下面EmandM的回答也表明[]会被视为false。 - Dillon Davis
1
@DillonDavis:它的建议是错误的。[] 是真值。 - Ry-
你的假设是数组被作为布尔值进行比较,但事实并非如此。 - Felix Kling
2个回答

11
在JS中的类型转换,特别是涉及到宽松相等性方面,是一个棘手的问题。始终回答“为什么特定的松散相等会这样评估”最好的方法是请参阅操作数类型的等式比较表
在这种情况下,我们可以看到对于[] == false,操作数A是一个对象,操作数B是一个布尔值,因此执行的实际比较将是ToPrimitive(A)== ToNumber(B)
右侧很简单;ToNumber(false)计算结果为0。做完了。
左侧更加复杂;您可以检查官方ECMAScript规范以获取有关ToPrimitive的完整文档,但您只需要知道,在这种情况下,它归结为A.valueOf().toString(),在空数组的情况下仅为空字符串""
因此,我们最终评估"" == 0。字符串/数字==比较在字符串上执行ToNumber操作,而ToNumber("")0,因此我们得到0 == 0,当然是true

0

双等号==在尝试检查相等性之前对值执行一定的类型强制转换。

因此,arr == arr返回true,就像您期望的那样,因为您实际上正在检查的是[] == [],并且等式两侧的类型相同。

arr ==!arr实际上是在检查[] == false。然后,==[]值执行类型强制转换。正如Hamms指出的那样,这不执行布尔转换,而是将[]转换为原始值,由于某些原因,它变成了一个空字符串。现在我们的等式是'' == false。这个操作的两边的类型仍然不同。所以类型强制转换再次启动,并且由于JavaScript中的真值和假值,''也被评估为false。方程现在变成了false == false,显然是true。


1
为什么 [] 也会被视为 false?如果这个说法是正确的,为什么 Boolean([]) 返回 true? - Isaac
如果 ( [ ] ) { //此代码运行 }。为什么 [ ] == false // true - msm082919
1
这并不完全准确;你说的对,情况归结为检查[] == false,但在这种情况下,JS实际上会将第一个操作数转换为其ToPrimitive值,而不是其ToBoolean值,而空数组的原始值实际上是空字符串。 - Hamms
新编辑的“真值和假值”部分仍然错误-字符串==布尔值并不使用字符串的真实性,而是在数值上进行比较。尝试 'x' == true'0' == false - Ry-
谢谢你的指点,Hamms的回答比这个更加完整。 - EmandM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接