究竟为什么这里的条件评估为真?
var condition = new Boolean(false);
if (condition == !condition)
alert("The more you know...");
究竟为什么这里的条件评估为真?
var condition = new Boolean(false);
if (condition == !condition)
alert("The more you know...");
分解它:
var condition = new Boolean(false);
这实际上是一个对象,并且condition.valueOf() === false
!{}
评估为假,因为{}
是真的(解释http://www.ecma-international.org/ecma-262/5.1/#sec-9.2)
所以检查是condition.valueOf() == false
,这是真的
您正在将对象 (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 调用时,采取以下步骤:
令 valueOf 为使用参数“valueOf”调用对象 O 的 [[Get]] 内部方法的结果。
如果 IsCallable(valueOf) 为真,则
一种。令 val 为调用 valueOf 的 [[Call]] 内部方法的结果,其中 O 作为 this 值和一个空参数列表。
湾。如果 val 是原始值,则返回 val。
因此它调用.valueOf()
对象上的方法,将我们带到15.6.4.3 Boolean.prototype.valueOf ( )
设 B 为 this 值。
如果 Type(B) 为布尔值,则令 b 为 B。
否则,如果 Type(B) 是 Object 并且 B 的 [[Class]] 内部属性的值是“Boolean”,则令 b 是 B 的 [[PrimitiveValue]] 内部属性的值。
否则抛出 TypeError 异常。
返回 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 中问“为什么”时得到的结果。
阅读逻辑布局的规范真的很有帮助,请参阅
从...开始:
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。
我从抽象等式比较算法中学到的一件事是,忘记直觉,按照步骤进行。
由于对象是真实的,它们的否定是false
,所以进入算法的是:
Boolean(false) == false
如果你一步一步走,你会得到:
Boolean(false) == 0 // Step 7
false == 0 // Step 9
0 == 0 // Step 6
true