这个问题在这里已有答案:
6862
2018-05-11 11:15
起源
叹了口气,我知道之前已经问过,但是SO不会让你搜索 {} 和 [] 因为他们不是言语。 - Barmar
这个视频的1:20 - Andy
答案:
预期成绩
当您添加两个数组时,一切都按预期工作:
[] + []//output''
转换 []
一个原始的第一次尝试 valueOf()
返回数组本身(this
):
var arr = [];
arr.valueOf() === arr
true
由于该结果不是原语,因此将调用toString()next并返回空字符串(这是一个原语)。因此,结果 [] + []
是两个空字符串的串联。
{} + [] // output: 0
添加数组和对象也符合我们的期望:
[] + {}//output '[object Object]'
说明:将空对象转换为字符串会产生以下结果。
String({})//output: '[object Object]'
因此,通过连接创建先前的结果 ""
和 "[object Object]"
。
出乎意料的结果
如果+的第一个操作数是一个空的对象文字(在Firefox控制台上看到的结果),事情会变得奇怪:
{} + {}//output: NaN
这里发生了什么?问题是JavaScript解释了第一个 {}
作为空代码块并忽略它。该 NaN
因此通过评估来计算 +{}
(加上第二个 {}
)。你在这里看到的加号不是二进制加法运算符,而是一个一元前缀运算符,它将其操作数转换为数字,方式与 Number()
。例如:
+"3.65"
3.65
以下表达式都是等效的:
+{}
Number({})
Number({}.toString()) // {}.valueOf() isn’t primitive
Number("[object Object]")
NaN
为什么是第一个 {}
解释为代码块?因为完整的输入被解析为语句,并且语句开头的花括号被解释为启动代码块。因此,您可以通过强制将输入解析为表达式来修复问题:
({} + {})//output: '[object Object][object Object]'
函数或方法的参数也总是被解析为表达式:
console.log({} + {})//output: [object Object][object Object]
在前面的解释之后,您不应该对以下结果感到惊讶:
{} + []//output: 0
同样,这被解释为后面的代码块 +[]
。以下表达式是等效的:
+[]
Number([])
Number([].toString()) // [].valueOf() isn’t primitive
Number("")
0
有趣的是,Node.js REPL以不同于Firefox或Chrome的方式解析其输入(甚至使用与Node.js相同的V8 JavaScript引擎)。以下输入被解析为表达式,结果不那么令人惊讶:
{} + {}//output: '[object Object][object Object]'
{} + []//output '[object Object]'
这样做的好处是更像是将输入用作console.log()的参数时得到的结果。但它也不像在程序中使用输入作为语句。
参考
9
2018-05-11 11:27