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

IT技术 javascript arrays properties
2021-01-18 11:33:41

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

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?

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

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

以下是此“功能”的更疯狂的后果:

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

var a = [0];
a == a // true
a == !a // also true, WTF?
6个回答

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

如果将所涉及的抽象算法翻译回 JS,则在评估时发生的情况2 == [2]基本上是这样的:

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

其中valueOf()for 数组返回数组本身,单元素数组的字符串表示是单个元素的字符串表示。

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

如您所见,其中涉及到很多幕后魔法,这就是为什么我通常只使用严格相等运算符的原因===

第一个和第二个示例更容易理解,因为属性名称始终是字符串,因此

a[[2]]

相当于

a[[2].toString()]

这只是

a["2"]

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

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

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

> +[2]
2
其实,没那么容易。[2] 转换为字符串会更接近但看看ecma-international.org/ecma-262/5.1/#sec-11.9.3
2021-04-02 11:33:41
其他人说 [2] 被转换为字符串。+"2"也是数字2。
2021-04-13 11:33:41
var a = [0, 1, 2, 3];
a[[2]] === a[2]; // this is true

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

顺便说一句,我想知道谁决定了这个优先级。是因为 [2] 有一个数字作为它的第一项,所以它转换为一个数字?或者是在将数组传递给 a[array] 时,它会尝试先将数组转换为数字,然后再转换为字符串。谁知道?

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

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

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

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

关于优先级的问题的答案:==适用ToPrimitive()于数组,数组又调用其toString()方法,因此您实际比较的是数字2与字符串"2"字符串和数字之间的比较是通过转换字符串来完成的
2021-04-08 11:33:41

对于这种==情况,这就是Doug Crockford建议始终使用===. 它不做任何隐式类型转换。

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

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

这很有趣,并不是说 [0] 既真又假,实际上

[0] == true // false

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

实际上,这是一种有趣的工作方式==如果您使用的是实际的显式类型转换(即Boolean([0])!![0]),你会发现,[0]将评估到true,因为它应该在布尔上下文:在JS,任何对象被认为是true
2021-03-30 11:33:41