8

可能重复:
空 JavaScript 数组的布尔值冲突

事实背后的理由是什么

[ ([] == false), ([] ? 1 : 2) ]

回报[true, 1]

换句话说,一个空列表在布尔上下文中逻辑上为真,但等于false

我知道使用===可以解决问题,但是这个显然完全不合逻辑的选择背后的解释是什么?

换句话说,这是否被认为是语言中的错误,是无意中发生的并且无法修复,因为为时已晚,或者真的在语言设计中有人认为拥有这种明显的疯狂很酷对许多程序员来说肯定很困惑吗?

关于这种情况如何发生的技术解释同时令人惊讶和恐惧,但我对这个设计背后的内容更感兴趣。

编辑

我接受了非常详细的 Nick Retallack 解释,即使它只是关于为什么[]==false是真的技术原因:令人惊讶的是,它发生的原因是[]转换为字符串是一个空字符串,而空字符串数值被特殊设置为 0 而不是显然更合乎逻辑NaN。例如,对于空对象,比较({}) == false返回 false,因为空对象的字符串表示不是空字符串。

我的好奇心仍然存在,这一切只是出乎意料(不幸的是,现在固化在一个标准中)。

4

2 回答 2

9

这里的混淆在于 JavaScript 中“虚假”的定义,它(与流行的看法相反)与== false.

Falsy 实际上是指具有 false 等效布尔值的值,而不是结果 == false 的表达式。JavaScript 中唯一的 Falsy 值是:false, 0, "", null, undefined, 和NaN. 因此,这些值中的任何一个——或任何评估为这些值之一的表达式(如在if语句中或使用三元运算符)——都是虚假的。

这是我在 JavaScript 中汇总的虚假/真实值的表格,应该有助于解释整个问题。 http://jsfiddle.net/philipwalton/QjSYG/

于 2012-05-11T17:32:47.060 回答
8

让我们获得技术。我将用ECMAScript Standard 262中的引号来解释逻辑。

表达式[] ? 1 : 2很简单:

11.12 条件运算符 (? : )

  • 令 lref 为评估 LogicalORExpression 的结果。
  • 如果ToBoolean(GetValue(lref))为真,则
    • 令 trueRef 为评估第一个 AssignmentExpression 的结果。
    • 返回 GetValue(trueRef)。
  • 别的
    • 设 falseRef 为计算第二个 AssignmentExpression 的结果。
    • 返回 GetValue(falseRef)

9.2 ToBoolean

  • 未定义:假
  • 空:假
  • 布尔值:结果等于输入参数(无转换)。
  • 数字:如果参数为 +0、0 或 NaN,则结果为假;否则结果为真。
  • String:如果参数为空字符串(长度为零),则结果为假;否则结果为真。
  • 对象:真

所以这是真的。


现在来看看使用双等号运算符时会发生什么。也许这将有助于解释为什么你不应该这样做。

== 的行为在第 11.9.3 节:抽象相等比较算法中进行了解释。

对于 x == y 其中 x = [] 和 y = false,会发生这种情况:

11.9.3:抽象等式比较算法

如果 Type(y) 为 Boolean,则返回比较结果 x == ToNumber(y)

9.3 ToNumber

如果参数为 false ,则结果为+0

现在我们有 [] == 0

11.9.3:抽象等式比较算法

如果 Type(x) 是 Object 并且 Type(y) 是 String 或 Number,则返回比较结果ToPrimitive(x) == y

9.1 ToPrimitive

返回对象的默认值。通过调用对象的[[DefaultValue]] 内部方法检索对象的默认值,并传递可选提示 PreferredType。本规范为 8.12.8 中的所有原生 ECMAScript 对象定义了 [[DefaultValue]] 内部方法的行为。

8.12.8 默认值:

当 O 的 [[DefaultValue]] 内部方法在没有提示的情况下被调用时,它的行为就好像提示是Number

  • 令 valueOf 为使用参数“valueOf”调用对象 O 的 [[Get]] 内部方法的结果。
  • 如果 IsCallable(valueOf) 为真,则
    • 令 val 为调用 valueOf 的 [[Call]] 内部方法的结果,其中 O 作为 this 值和一个空参数列表。
    • 如果 val 是原始值,则返回 val
  • 令 toString 为使用参数“toString”调用对象 O 的 [[Get]] 内部方法的结果。
  • 如果 IsCallable(toString) 为真,则
    • 令 str 为调用toString的 [[Call]] 内部方法的结果,其中 O 作为 this 值和一个空参数列表。
    • 如果 str 是原始值,则返回 str

我假设这首先尝试 valueOf 然后拒绝它,因为结果与您开始使用的数组相同。然后它在 Array 上调用 toString,这似乎被普遍实现为一个逗号分隔的值列表。对于像这样的空数组,这会导致空字符串。

现在我们有 '' == 0

11.9.3:抽象等式比较算法

如果 Type(x) 是 String 且 Type(y) 是 Number,则返回比较结果ToNumber(x) == y

9.3.1 ToNumber 应用于字符串类型

为空或仅包含空格的 StringNumericLiteral 将转换为+0

现在我们有 0 == 0

11.9.3:抽象等式比较算法

如果 x 与 y 的数值相同,则返回 true

惊人的。这是真的。到达这里的方式相当复杂。

于 2012-05-11T17:32:55.793 回答