Javascript明显的疯狂

时间:2012-05-11 17:29:35

标签: javascript language-design

  

可能重复:
  Conflicting boolean values of an empty JavaScript array

背后的理由是什么?
[ ([] == false), ([] ? 1 : 2) ]

返回[true, 1]

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

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

换句话说,这被认为是语言中的一个错误,一些无意识的事情刚刚发生并且无法修复,因为它太晚或者真的在设计语言时有人认为这种明显的疯狂很酷我确定很多程序员都很困惑?

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

修改

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

我的好奇心仍然是所有这一切都是未曾预料到的(现在不幸在标准中固化)。

2 个答案:

答案 0 :(得分:9)

这里的混淆是围绕JavaScript中“falsy”的定义,(与普遍看法相反)与== false不同。

Falsy实际上是指一个布尔值等于false的值,而不是一个结果为== false的表达式。 JavaScript中唯一的Falsy值包括:false0""nullundefinedNaN。因此,任何这些值 - 或任何评估其中一个值的表达式(如if语句或使用三元运算符)都是假的。

这是我在JavaScript中汇总了falsy / truthy值的表格,可以帮助解释整个问题。 http://jsfiddle.net/philipwalton/QjSYG/

答案 1 :(得分:8)

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

表达式[] ? 1 : 2非常简单:

  

11.12条件运算符(?:)

     
      
  • 让lref成为评估LogicalORExpression的结果。
  •   
  • 如果 ToBoolean(GetValue(lref))为真,那么      
        
    • 设trueRef是评估第一个AssignmentExpression的结果。
    •   
    • 返回GetValue(trueRef)。
    •   
  •   
  • 否则      
        
    • 设falseRef是评估第二个AssignmentExpression的结果。
    •   
    • 返回GetValue(falseRef)
    •   
  •   
     

9.2 ToBoolean

     
      
  • 未定义:false
  •   
  • Null:false
  •   
  • Boolean:结果等于输入参数(无转换)。
  •   
  • Number:如果参数为+ 0,0或NaN,则结果为false;否则结果是真的。
  •   
  • String:如果是,则结果为false   参数是空字符串(其长度为零);否则   结果是真的。
  •   
  • 对象:true
  •   

所以这是真的。


现在,当您使用double equals运算符时会发生什么。也许这有助于解释为什么你永远不应该这样做。

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

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

  

11.9.3:抽象等式比较算法

     

如果Type(y)是布尔值,则返回比较结果x == ToNumber(y)

     

9.3 ToNumber

     

如果参数是,则结果为 +0   的

现在我们有[] == 0

  

11.9.3:抽象等式比较算法

     

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

     

9.1 ToPrimitive

     

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

     

8.12.8 DefaultValue:

     

当调用O的[[DefaultValue]]内部方法时没有   提示,然后它的行为就好像提示是数字

     
      
  • 设valueOf是使用参数“valueOf”调用对象O的[[Get]]内部方法的结果。
  •   
  • 如果IsCallable(valueOf)为真,那么,      
        
    • 设val是调用valueOf的[[Call]]内部方法的结果,其中O为此值和空参数列表。
    •   
    • 如果val是原始值,则返回val
    •   
  •   
  • 让toString成为使用参数“toString”调用对象O的[[Get]]内部方法的结果。
  •   
  • 如果IsCallable(toString)为真,那么,      
        
    • 设str为调用 toString 的[[Call]]内部方法的结果,其中O为此值和空参数列表。
    •   
    • 如果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

真棒。这是真的。虽然这里有相当复杂的方式。