在JavaScript中对两个空对象或空数组进行加法操作

11

当我在玩javascript时,发现了以下控制台输出:

  1. [] + [] // 输出: ""
  2. [] + {} // 输出: [object Object]
  3. {} + [] // 输出: 0
  4. {} + {} // 输出: NaN

请问有人能解释一下这些输出背后的逻辑吗?我觉得这是一个非常奇怪的行为,但我猜可能它背后有一些逻辑。

提前感谢。


2
叹气,我知道这个问题以前已经被问过了,但是SO不允许你搜索{}[],因为它们不是单词。 - Barmar
1
请在此处查看视频1:20的内容。 - Andy
1个回答

9

期望的结果

当你在添加两个数组时,一切都按照预期工作:

[] + []//output''

[]转换为原始类型时,首先尝试使用valueOf()方法,该方法返回数组本身(this):
var arr = [];
arr.valueOf() === arr
true

由于该结果不是原始值,因此接下来调用toString(),并返回空字符串(这是一个原始值)。因此,[] + [] 的结果是两个空字符串的拼接。
{} + [] // 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不同(即使Chrome使用与Node.js相同的V8 JavaScript引擎)。以下输入被解析为表达式,结果并不令人惊讶:

{} + {}//output: '[object Object][object Object]'
{} + []//output '[object Object]'

这种方法的优点是更像使用输入作为console.log()参数时获得的结果。但它也不像在程序中使用输入作为语句那样直观。 参考资料

JavaScript中{} + {}是什么?


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