当我以为我理解了JavaScript中的类型转换时,我偶然发现了这个:
+[]; // 0
Number([]); // 0
我的第一个想法是我应该得到NaN,就像我尝试将空对象转换为数字一样:
+{}; // NaN
Number({}); // NaN
我一直在搜索这个问题一段时间没有任何成功......
有人可以解释为什么它会转换为0而不是NaN吗?
这种行为是标准的吗?
感谢。
答案 0 :(得分:22)
简而言之,有两个要点:
toString
方法返回空字符串。Number
constructor called as a function(例如+"" === 0;
)将强制为零。例如,我们可以使用定义toString
方法的对象,并返回一个空字符串以获得相同的结果:
var obj = { toString: function () { return "";} };
+obj; // 0
Number(obj); // 0
此行为完全符合标准。
现在答案很长:
两者,unary plus operator和Number
constructor called as a function都在内部使用ToNumber
抽象操作。
ToNumber
将使用另外两项内部操作,ToPrimitive
和[[DefaultValue]]
。
当ToNumber
操作应用于Object(例如示例中的空数组)时,它会调用ToPrimitive
操作,以获取代表性原始值并再次使用ToNumber
调用该值 [1] 。
ToPrimitive
操作接收两个参数,一个Value(这是你的数组对象)和一个提示类型,在这种情况下是“Number”,因为我们想进行数字转换。
ToPrimitive
调用[[DefaultValue]]
内部方法,也使用“数字”提示类型。
现在,由于我们使用的是“数字”提示类型,[[DefaultValue]]
内部方法现在将首先尝试在对象上调用valueOf
方法。
数组对象没有特定的valueOf
方法,该方法是从Object.prototype.valueOf
继承的方法,此方法只返回对对象本身的引用。
由于valueOf
方法没有产生原始值,现在调用toString
方法,并产生一个空字符串(这是一个原始值) ),然后ToNumber
操作将尝试进行字符串数字转换,最后以0
[1] 结束。
但现在你可能想知道,为什么一个空字符串强制为零?
+""; // 0
在ToNumber
internal operation is applied to a String type,StringNumericLiteral
制作时使用完整的语法。
NumericLiteral之间存在一些差异,其中一个区别在于:
StringNumericLiteral为空或仅包含空格,将转换为+0。