为什么JavaScript 2中的2 == ?

我最近在JavaScript中发现了2 == [2] 。 事实certificate,这个怪癖有一些有趣的结果:

 var a = [0, 1, 2, 3]; a[[2]] === a[2]; // this is true 

同样,下面的作品:

 var a = { "abc" : 1 }; a[["abc"]] === a["abc"]; // this is also true 

即使是陌生人,这也适用:

 [[[[[[[2]]]]]]] == 2; // this is true too! WTF? 

这些行为在所有浏览器中都是一致的。

任何想法,为什么这是一个语言function?

以下是这个“特征”更疯狂的后果:

 [0] == false // true if ([0]) { /* executes */ } // [0] is both true and false! var a = [0]; a == a // true a == !a // also true, WTF? 

这些例子是由jimbojw http://jimbojw.com名声以及walkingeyerobot发现的 。

您可以在ECMA-spec中查找比较algorithm(ECMA-262的相关章节,针对您的问题的第3版:11.9.3,9.1,8.6.2.6)。

如果将涉及到的抽象algorithm转换回JS,那么在评估2 == [2]时会发生什么情况基本上是这样的:

 2 === Number([2].valueOf().toString()) 

其中数组的valueOf()返回数组本身,一个元素数组的string表示forms是单个元素的string表示forms。

这也解释了第三个例子, [[[[[[[2]]]]]]].toString()仍然是string2

正如你所看到的,涉及到很多幕后的魔法,这就是为什么我通常只使用严格的等号运算符===

第一个和第二个例子更容易遵循,因为属性名称总是string,所以

 a[[2]] 

相当于

 a[[2].toString()] 

这只是

 a["2"] 

请记住,即使数字键被视为属性名称(即string),在任何数组魔术发生之前。

这是因为==运算符的隐式types转换。

与数字相比,[2]被转换为数字2。 尝试[2]上的一元+运算符。

 > +[2] 2 
 var a = [0, 1, 2, 3]; a[[2]] === a[2]; // this is true 

在等式的右边,我们有一个[2],它返回一个数值types的值为2.在左边,我们首先创build一个单个对象为2的新数组。然后我们调用一个[(数组在这里)]。 我不知道这是评估一个string或数字。 2或“2”。 让我们先拿起string案例。 我相信一个[“2”]会创build一个新的variables,并返回null。 null!== 2.所以让我们假设它实际上是隐式转换为数字。 一个[2]将返回2. 2和2匹配types(所以===工程)和价值。 我认为这是隐式转换数组,因为[值]需要一个string或数字。 它看起来像数字具有更高的优先级。

在旁注中,我想知道谁决定了这个优先。 是因为[2]有一个数字,因为它的第一个项目,所以它转换为数字? 或者,当将数组传递给[数组]时,首先尝试将数组转换为数字,然后是string。 谁知道?

 var a = { "abc" : 1 }; a[["abc"]] === a["abc"]; 

在这个例子中,你正在创build一个名为abc的成员对象。 等式的右边非常简单; 它相当于a.abc。 这将返回1.左侧首先创​​build一个[“abc”]的文字数组。 然后通过传入新创build的数组来search对象上的variables。 由于这需要一个string,它将数组转换为一个string。 这现在计算为一个[“abc”],它等于1. 1和1是相同的types(这就是为什么===工作)和相等的价值。

 [[[[[[[2]]]]]]] == 2; 

这只是一个隐含的转换。 ===在这种情况下不起作用,因为types不匹配。

对于==情况,这就是Doug Crockfordbuild议始终使用=== 。 它不会执行任何隐式types转换。

对于===的示例,隐式types转换是在调用相等运算符之前完成的。

 [0] == false // true if ([0]) { /* executes */ } // [0] is both true and false! 

这很有趣,实际上并不是[true]和false都是真的

 [0] == true // false 

()运算符是javascript的有趣的处理方式。

一个项目的数组可以被视为项目本身。

这是由于鸭子打字。 由于“2”== 2 == [2]可能更多。

为其他答案添加一点细节…当一个Array与一个Number进行比较时,Javascript将使用parseFloat(array)转换该Array 。 您可以在控制台(例如Firebug或Web Inspector)中自己尝试一下,看看不同的Array值被转换为什么。

 parseFloat([2]); // 2 parseFloat([2, 3]); // 2 parseFloat(['', 2]); // NaN 

对于Array s, parseFloatArray的第一个成员执行操作,并丢弃其余的部分。

编辑:根据Christoph的细节,这可能是它在内部使用较长的forms,但结果始终与parseFloat相同,所以您始终可以使用parseFloat(array)作为速记,以便确定如何转换。

你在每种情况下比较2个对象..不要使用==,如果你正在考虑比较,你有===而不是==。 ==可以经常给疯狂的影响。 在语言中寻找好的部分:)

问题编辑部分的解释:

第一个例子

 [0] == false // true if ([0]) { /* executes */ } // [0] is both true and false! 

首先将types[0]转换为原始值,按照上面的Christoph的回答,我们有“0”( [0].valueOf().toString()

 "0" == false 

现在,typecast布尔值(假)为数字,然后string(“0”)为数字

 Number("0") == Number(false) or 0 == 0 so, [0] == false // true 

至于if语句,如果if条件本身没有明确的比较,则条件评估为值。

只有6个falsy值 :false,null,undefined,0,NaN和空string“”。 而任何不是虚假价值的东西都是真正的价值。

由于[0]不是一个falsy值,它是一个真值, if语句的计算结果为true并执行语句。


第二个例子

 var a = [0]; a == a // true a == !a // also true, WTF? 

再次input将值转换为原始值,

  a = a or [0].valueOf().toString() == [0].valueOf().toString() or "0" == "0" // true; same type, same value a == !a or [0].valueOf().toString() == [0].valueOf().toString() or "0" == !"0" or "0" == false or Number("0") == Number(false) or 0 = 0 // true