为什么在JavaScript中,"" == [null] 的结果是true?

54

10
一个只有一个null元素的数组会被强制转换为字符串,也就是调用了.join(',')方法。由于只有一个元素,所以它变成了(string)null,也就是空字符串。 - scragar
9
如果你想比较两种不同类型的东西,使用严格相等运算符===,并将它们转换为相同的类型。 - Paul S.
2
相关内容:http://dorey.github.io/JavaScript-Equality-Table/ - Mike G
6个回答

76

"抽象相等比较算法"包含许多部分,但这里重要的是:

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

(也有一个镜像版本)。因此,由于 "" 是字符串而 [null] 是对象,我们必须先通过调用 ToPrimitive([null])[null] 转换为字符串。当它被要求将一个对象实例转换为原始值时,这是一个内部操作,描述如下:

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

现在,[[DefaultValue]] 内部操作将调用对象的 .toString() 方法并返回该值。在浏览器控制台中尝试使用 [null].toString()
> [null].toString()
""

这就是它的原理。

编辑:为什么[null].toString()会变成空字符串呢?因为对于数组实例,.toString()操作总是调用.join(),而对于nullundefined值,.join()总是返回空字符串。因此,一个只包含一个null的数组最终会变成一个单独的空字符串。


1
我认为你缺少了一步;为什么[null].toString()不返回"null" - Izkata
8
Array.prototype.toString() 方法返回调用该数组的this.join()的结果,而.join()方法将nullundefined条目呈现为空字符串。因此,具有一个null条目的数组呈现为空字符串。 - Pointy
3
不,不是这样。在这些情况下,字符串会被转换为另一个参数的类型。在OP的问题中,另一个参数被转换为字符串。 - Aaron Dufour
1
@Pointy 我的意思是,我认为将那个评论添加到答案中会很好。 - Izkata
1
@sulest:我们讨论它的原因是因为很多人会犯这个错误。对我来说(我相信也有很多其他人),其他编程语言使用==表示JavaScript中的===,所以需要通过艰苦的学习才能掌握... ;) - Scott Stafford
显示剩余5条评论

17
根据Javascript的奥秘type-conversion规则,这是符合规则#8的:

如果x的类型是字符串或数字,y的类型是对象,则返回比较x == ToPrimitive(y)的结果。

因此,比较的是将x = ""y = [null]使用ToPrimitive转换为字符串后的结果。将只有一个null元素的数组转换为字符串会得到一个空字符串(因为Array.toString()返回逗号分隔的值列表),因此它们相等。

12

为什么 "" == [null] 的结果是 true?

因为你在使用非严格相等运算符 ==比较一个字符串和一个数组,所以它会在比较之前尝试将值转换为相同的类型。

具体来说,会发生以下情况:

  1. 你将一个字符串与一个对象进行比较,所以对象被转换为一个字符串:
  2. 当一个数组被转换为原始值时,它的 .toString() 方法会被调用(正如其他答案中详细解释的那样),这相当于调用 .join()
  3. 对于只包含 undefinednull 值的单元素数组,返回空字符串
  4. 最终等价于空字符串
这第三步是出人意料的([null]+"" != null+""),如果它实际上将其转换为字符串,结果将会是"null",你的相等性将会是假的。

2
让我们看一下规范并按照每个步骤执行。
通过抽象相等比较算法(§11.9.3)

  1. typeof ""; // stringtypeof [null]; // object,因此不适用
  2. 既不是null也不是undefined,因此不适用
  3. 与2相同
  4. 不是数字,不适用
  5. 与4相同
  6. 不是bool,不适用
  7. 再次不适用
  8. 最后,有一个适用的,现在我们需要知道ToPrimitive([null])
§9.1 ToPrimitive针对对象说,我们需要计算[[DefaultValue]](§8.12.8),其中的第1和第2点说如果你可以使用.toString并且它返回一个字符串,则返回该字符串,因此
[null].toString(); // ""

现在我们正在执行比较"" == "",根据抽象相等比较算法的第1点d,结果为true

如果Type(x)字符串,则如果xy是完全相同的字符序列(长度相同且对应位置上的字符相同),则返回true。否则,返回false


1
JavaScript是弱类型语言;你可以使用以下方法获取错误结果:
"" === [null]

-1

值 null 是 JavaScript 字面量,表示 null 或“空”值,即没有对象值存在。它是 JavaScript 的原始值之一。

值 null 是字面量(不像 undefined 可以是全局对象的属性)。在 API 中,null 经常在需要对象但没有相关对象时被检索。当检查 null 或 undefined 时,请注意等式(==)和恒等式(===)运算符之间的差异(前者执行类型转换)。

typeof null        // object (bug in ECMAScript, should be null)
typeof undefined   // undefined
null === undefined // false
null  == undefined // true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接