26

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

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

4 回答 4

24

分解它:

var condition = new Boolean(false);

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

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

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

于 2013-08-06T03:46:24.123 回答
23

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

[object Boolean] == false

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

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

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

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

[object Boolean] == 0

如您所见,由于==. 所以现在我们将一个对象与一个数字进行比较,因此以下几点适用:

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

所以这里它现在正试图将对象强制为其原始值。从9.1 ToPrimitive 开始,在对象上调用时:

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

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

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

因此,这将我们带到以下行为:

当 O 的 [[DefaultValue]] 内部方法用提示 Number 调用时,采取以下步骤:

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

  2. 如果 IsCallable(valueOf) 为真,则

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

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

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

  1. 设 B 为 this 值。

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

  3. 否则,如果 Type(B) 是 Object 并且 B 的 [[Class]] 内部属性的值是“Boolean”,则令 b 是 B 的 [[PrimitiveValue]] 内部属性的值。

  4. 否则抛出 TypeError 异常。

  5. 返回 B.

因此,您可以从第 3 步中看到,它将返回[[PrimitiveValue]]对象的 。这将我们带到15.6.2.1 新的布尔值(值)

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

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

false == 0

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

6)如果 Type(x) 是 Boolean,返回比较结果 ToNumber(x) == y。

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

0 == 0

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


故事的寓意……这就是当你在 JavaScript 中问“为什么”时得到的结果。

于 2013-08-06T04:39:26.080 回答
7

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

从...开始:

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

然后

y = false;

因为布尔对象被认为是布尔对象,而是日常对象,所以ToBoolean(x) 评估为true!true评估为false

抽象等式比较算法

第 1 轮: 第 7 步

如果 Type(y) 是 Boolean,则返回比较结果 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) 是 Boolean,则返回比较 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。

于 2013-08-06T04:28:16.663 回答
4

我从抽象等式比较算法中学到的一件事是,忘记直觉,按照步骤进行。

由于对象是真实的,它们的否定是false,所以进入算法的是:

Boolean(false) == false

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

Boolean(false) == 0  // Step 7
false == 0           // Step 9
0 == 0               // Step 6
true
于 2013-08-06T04:31:57.427 回答