如果([] == false)为真,为什么([] || true)的结果是[]?

3

我刚刚在进行一些测试,发现了这个奇怪的问题:

[] == false

返回true,这是有道理的,因为双等号仅比较内容而不比较类型并尝试进行类型强制转换。但如果它比较内容并返回true,那就意味着[]是假值(如果你执行[] == true也会得到false),这意味着:

[] || false

应该返回 false,但它返回 [ ],这是为什么呢?这是因为 [] 被认为是一个 truthy 值,即使它是一个空数组。

另一个例子:

"\n  " == 0

给出 true,但 "\n " || false 返回 "\n "?这是为什么呢,还是只是一种怪异现象?
当我在 C 中尝试时,我们得到的是:
int x = "\n " == 0;
printf("%d\n", x);

int y = "\n " || 0;
printf("%d\n", y);

输出:

0
1

这是有道理的,但考虑到C对Javascript的影响,行为会有所不同。

1
[] 是一个 真值 表达式,但 == 执行 强制转换。这些规则在 11.9.3 抽象相等比较算法 中有所涵盖(搜索 "Equality Comparison Algorithm" 可能会找到相关问题)。 - user2864740
看这个令人震惊的 JS:你所有的逗号都属于 Array - Greg Burghardt
3个回答

4
类型转换与真假值无关。
真值和假值的定义由规范中定义的 ToBoolean 函数确定,而 [] 确实是真值。
另一方面,[] == false 返回 true 是因为在表达式求值过程中发生了 类型转换
类型转换规则指出,对于 x == y

如果 Type(y) 为布尔类型,则返回比较 x == ToNumber(y) 的结果。

ToNumber 对 false 的结果为 0,因此我们得到了 [] == 0 的求值结果。根据相同的规则,

如果 Type(x) 为对象且 Type(y) 为字符串或数字,则返回比较 ToPrimitive(x) == y 的结果。

ToPrimitive的结果是一个空字符串。现在我们有"" == 0。回到我们的类型转换规则

如果x的类型是字符串并且y的类型是数字,返回比较ToNumber(x) == y的结果。

ToNumber对于""的结果是0,因此最终评估为0 == 0,结果为true


在JS中没有ToBoolean(),因此如果找不到更好的匹配项,则类型转换通常会转换为布尔值。如果可以将其作为字符串或数字进行比较,则它将优先选择这种方式,而不是停留在true/false。 - dandavis
@dandavis,正如我所说的那样,“ToBoolean”是由规范定义的。它是JS解释器使用的函数,而不是JS函数。 - dee-see
好的,你是对的,但这如何解释为什么[]被转换为字符串来与false进行比较? - dandavis
@dandavis,所有的链接都在我给出的内容中,但我在我的回答中编辑了一个完整的解释。 - dee-see
@dandavis 很高兴你欣赏! - dee-see

3

“即使有强制转换,'Is false'与'在布尔上下文中评估为false'是不同的。 obj == false询问对象是否为布尔值false,而不是在布尔上下文中评估为这样的情况。

您可以使用(!!obj)在布尔上下文中评估对象。

[] == false;         // true
(!![]) == false;     // false

"\n  " == false;     // true
(!!"\n  ") == false; // false

Not JavaScript. Whoops. - cdhowie
@dandavis 已修复。谢天谢地,我的答案基本前提仍然有效,只是更改了一些语法。 - cdhowie

0

来自ECMA-262 5.1(第83页):

如果ToBoolean(lval)为true,则返回lval

[] || false; // []

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