为什么JavaScript中有2 == [2]?

Xav*_*avi 163 javascript arrays properties

我最近2 == [2]在JavaScript中发现了.事实证明,这个怪癖有几个有趣的后果:

var a = [0, 1, 2, 3];
a[[2]] === a[2]; // this is true
Run Code Online (Sandbox Code Playgroud)

同样,以下工作:

var a = { "abc" : 1 };
a[["abc"]] === a["abc"]; // this is also true
Run Code Online (Sandbox Code Playgroud)

更奇怪的是,这也有效:

[[[[[[[2]]]]]]] == 2; // this is true too! WTF?
Run Code Online (Sandbox Code Playgroud)

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

知道为什么这是一个语言功能吗?

以下是这个"功能"的更为疯狂的后果:

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

var a = [0];
a == a // true
a == !a // also true, WTF?
Run Code Online (Sandbox Code Playgroud)

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

Chr*_*oph 133

您可以在ECMA规范中查找比较算法(ECMA-262的相关部分,第3版针对您的问题:11.9.3,9.1,8.6.2.6).

如果将所涉及的抽象算法转换回JS,那么在评估时会发生什么2 == [2]:

2 === Number([2].valueOf().toString())
Run Code Online (Sandbox Code Playgroud)

其中valueOf()为阵列返回数组本身和一元件阵列的串的表示是单个元件的字符串表示.

这也解释了第三个例子,因为[[[[[[[2]]]]]]].toString()它仍然只是字符串2.

正如你所看到的,涉及到很多幕后魔术,这就是我通常只使用严格相等运算符的原因===.

第一个和第二个例子更容易理解,因为属性名称总是字符串,所以

a[[2]]
Run Code Online (Sandbox Code Playgroud)

相当于

a[[2].toString()]
Run Code Online (Sandbox Code Playgroud)

这只是

a["2"]
Run Code Online (Sandbox Code Playgroud)

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


Che*_*try 10

这是因为==运算符的隐式类型转换.

与Number相比,[2]转换为Number为2.+在[2]上尝试一元运算符.

> +[2]
2
Run Code Online (Sandbox Code Playgroud)


Sha*_*awn 10

var a = [0, 1, 2, 3];
a[[2]] === a[2]; // this is true
Run Code Online (Sandbox Code Playgroud)

在等式的右边,我们有a [2],它返回一个值为2的数字类型.在左边,我们首先创建一个单个对象为2的新数组.然后我们调用[(数组在这里)].我不确定这是评估字符串还是数字.2,或"2".让我们首先采取字符串案例.我相信一个["2"]会创建一个新变量并返回null.null!== 2.所以我们假设它实际上是隐式转换为数字.a [2]会返回2. 2和2匹配类型(所以===有效)和值.我认为它隐式地将数组转换为数字,因为[value]需要一个字符串或数字.看起来数字优先级更高.

在旁注中,我想知道谁确定了优先权.是因为[2]有一个数字作为它的第一个项目,所以它转换成一个数字?或者是当将数组传递到[数组]时,它会尝试先将数组转换为数字,然后再转换为数组.谁知道?

var a = { "abc" : 1 };
a[["abc"]] === a["abc"];
Run Code Online (Sandbox Code Playgroud)

在此示例中,您将创建一个名为a的对象,其中包含名为abc的成员.等式的右边非常简单; 它相当于a.abc.返回1.左侧首先创​​建一个["abc"]的文字数组.然后,通过传入新创建的数组,在对象上搜索变量.由于这需要一个字符串,因此它将数组转换为字符串.这现在评估为["abc"],等于1.1和1是相同的类型(这就是为什么===有效)和相等的值.

[[[[[[[2]]]]]]] == 2; 
Run Code Online (Sandbox Code Playgroud)

这只是一种隐式转换.===在这种情况下不起作用,因为存在类型不匹配.


Dan*_*ook 8

对于这种==情况,这就是Doug Crockford建议总是使用的原因===.它不进行任何隐式类型转换.

对于示例===,隐式类型转换在调用相等运算符之前完成.


Ale*_*mov 7

[0] == false // true
if ([0]) { /* executes */ } // [0] is both true and false!
Run Code Online (Sandbox Code Playgroud)

这很有意思,实际上并不是[0]既是真也是假

[0] == true // false
Run Code Online (Sandbox Code Playgroud)

这是javascript处理if()运算符的有趣方式.

  • 实际上,这是有趣的方式`==`有效; 如果你使用一个实际的显式转换(即`Boolean([0])`或`!! [0]`),你会发现`[0]`将在布尔上下文中评估为'true`,因为它应该:在JS中,任何对象都被认为是"true" (4认同)

Óla*_*age 6

可以将一个项目的数组视为项目本身.

这是因为鸭子打字.因为"2"== 2 == [2]而且可能更多.

  • 这与鸭子打字无关,而是与弱打字有关,即隐式类型转换 (14认同)
  • 另外,我不认为鸭子打字是正确的词.在比较之前,它更多地与`==`运算符执行的隐式类型转换有关. (8认同)
  • 因为他们不匹配类型.在第一个例子中,首先评估左侧,然后它们最终匹配类型. (4认同)
  • Chetan和Christoph说的是什么. (2认同)