为什么一个空数组会转换成0?+[]

22

就在我以为自己对JavaScript中的类型转换有所了解时,我遇到了这个问题:

+[]; // 0
Number([]); // 0

我的第一反应是会得到NaN,就像把一个空对象转换成数字时一样:

+{}; // NaN
Number({}); // NaN

我已经搜索了一段时间,但没有任何成功...

有人能解释一下为什么它会被转换为0而不是NaN吗?

这种行为是否标准?

谢谢。

1个回答

33
简而言之,有两个关键点: 例如,我们可以使用一个定义了toString方法并返回一个空字符串的对象来获得相同的结果:
var obj = { toString: function () { return "";} };
+obj; //  0
Number(obj); // 0

这种行为是完全标准的。
现在给出详细解释:
无论是一元加操作符还是Number构造函数作为函数调用,内部都使用了ToNumber抽象操作。 ToNumber将使用另外两个内部操作,ToPrimitive[[DefaultValue]]
当对一个对象应用ToNumber操作时,例如你的示例中的空数组,它会调用ToPrimitive操作,以获取一个代表性的原始值,并再次使用该值调用ToNumber[1]ToPrimitive操作接收两个参数,一个是值(即你的数组对象),另一个是提示类型,在这种情况下是"Number",因为我们想进行数值转换。 ToPrimitive调用[[DefaultValue]]内部方法,同样使用"Number"提示类型。
现在,由于我们使用的提示类型是"Number",[[DefaultValue]]内部方法将首先尝试调用对象上的valueOf方法。
数组对象没有特定的valueOf方法,该方法是从Object.prototype.valueOf继承而来,该方法只是简单地返回对对象本身的引用。

由于valueOf方法未产生一个原始值,现在调用toString方法,它生成一个空字符串(这是一个原始值),然后ToNumber操作将尝试进行字符串到数字的转换,最终得到0[1]

但是现在你可能会想,为什么一个空字符串强制转换成零?

+""; // 0

当将ToNumber内部操作应用于String类型时,有一个完整的语法,即StringNumericLiteral产生式。

它与NumericLiteral之间有一些差异,其中之一是:

一个空的或只包含空格的StringNumericLiteral会被转换为+0。


2
+1 数组在 JavaScript 中实际上是一种对象类型,因此它具有 toString() 方法。 - BoltClock
为什么数组对象没有valueOf方法? - FluffyBeing

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