为什么(条件==!条件)在JavaScript中为真?

时间:2013-08-06 03:43:49

标签: javascript

究竟为什么这里的条件评估为真?

var condition = new Boolean(false);
if (condition == !condition)
    alert("The more you know...");

4 个答案:

答案 0 :(得分:24)

分解:

var condition = new Boolean(false);

这实际上是一个对象,condition.valueOf() === false

!{}评估为false,因为{}为真(解释http://www.ecma-international.org/ecma-262/5.1/#sec-9.2

所以检查是condition.valueOf() == false,这是真的

答案 1 :(得分:23)

您正在将对象(LHS)与布尔false(RHS)进行比较。

[object Boolean] == false

==运算符根据ECMAScript定义的抽象等式比较算法执行类型强制。 11.9.3抽象等式比较算法

与您的代码相关的是该算法的以下几点(其中x是LHS,y是RHS)

  

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

请注意,它实际上首先尝试将布尔值转换为数字。 false布尔值转换为数字0,现在我们有了这个:

[object Boolean] == 0

如您所见,由于==,它递归地输入相同的算法。所以现在我们将一个对象与一个数字进行比较,因此适用以下几点:

  

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

所以现在它正在尝试将对象强制转换为原始值。从 9.1 ToPrimitive ,在对象上调用时:

  

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

所以你可以看到它想要对象的[[DefaultValue]]。这将我们带到 8.12.8 [[DefaultValue]] ,它需要一个“提示”。因为它没有收到“提示”,所以它的行为就像提示是“数字”一样。

  

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

这样就会带来以下行为:

  

当使用提示号调用O的[[DefaultValue]]内部方法时,将执行以下步骤:

     
      
  1. 设valueOf是使用参数“valueOf”调用对象O的[[Get]]内部方法的结果。

  2.   
  3. 如果IsCallable(valueOf)为真,那么

         

    一个。设val是调用valueOf的[[Call]]内部方法的结果,其中O为此值和空参数列表。

         

    湾如果val是原始值,则返回val。

  4.   

所以它调用对象上的.valueOf()方法,将我们带到 15.6.4.3 Boolean.prototype.valueOf()

  
      
  1. 设B为此值。

  2.   
  3. 如果Type(B)是布尔值,则令b为B。

  4.   
  5. 如果Type(B)是Object并且B的[[Class]]内部属性的值是“Boolean”,那么令b为B的[[PrimitiveValue]]内部属性的值

  6.   
  7. 否则抛出TypeError异常。

  8.   
  9. 返回b。

  10.   

因此,您可以从第3步看到它将返回对象的[[PrimitiveValue]]。这将我们带到 15.6.2.1 new Boolean(value)

  

新构造的Boolean对象的[[PrimitiveValue]]内部属性设置为ToBoolean(value)。

因此您可以看到,您最终会获得最初传递给构造函数的值的ToBoolean值,即false。它的ToBoolean值显然是false,所以现在你的比较是:

false == 0

由于类型仍然不匹配,它将转到原始算法中的第6点:

  

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

所以它现在想要将布尔值false转换为数字。这与上面所做的类似。值false会转换为值0,因此现在我们有:

0 == 0

最后我们有一个类型匹配的比较,因此通过比较值,它的行为与严格的===对应物相同。显然,0确实等于0,因此我们得到true


故事的道德......当你在JavaScript中询问“为什么”时,这就是你得到的。

答案 2 :(得分:7)

只是阅读逻辑布局的规范真的很有帮助,参见

开始于:

var x = new Boolean(false);
var y = !x;

然后

y = false;

因为布尔对象被认为是布尔值而是日常对象,ToBoolean(x) evaluates to true!true evaluates to false

The Abstract Equality Comparison Algorithm

第1轮:第7步

  

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

y = 0; //ToNumber(false) is 0

第2轮:第9步

  

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

x = false //Basically ends up calling x.valueOf()

第3轮:第6步

  

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

x = 0; //ToNumber(false) is 0

最后:第1步

  

如果Type(x)与Type(y)相同,那么

步骤1 C

  

如果Type(x)是Number,那么

步骤1 C iii

  

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

答案 3 :(得分:4)

我从The Abstract Equality Comparison Algorithm学到的一件事是,忘记直觉,并按照步骤进行。

由于对象是真实的,它们的否定是false,因此算法的内容是:

Boolean(false) == false

如果你一步一步走,你会得到:

Boolean(false) == 0  // Step 7
false == 0           // Step 9
0 == 0               // Step 6
true