[] + {} 和 {} + []一样吗?

@fwon 2017-03-01 07:29:27发表于 fwon/blog

这道题跟之前提到的[] == ![] 有异曲同工之妙,都是涉及到了隐式的强制类型转换。同样,我们直接开门见山,总结下加号操作符的运算规则。下面规则判断权重由上往下。

  1. 两个操作数都是数值 时,执行常规的数值加法计算。但有几个值的考虑
  • 如果有一个操作数是NaN, 则结果是NaN;
  • Infinity 加 Infinity 结果是 Infinity;
  • -Infinity 加 -Infinity 结果是 -Infinity;
  • Infinity 加 -Infinity 结果是NaN;
  • +0 加 +0 结果是+0;
  • -0 加 -0 结果是 -0;
  • +0 加 -0 结果是+0;
  1. 当有 一个操作数是字符串 时,应用如下规则:
  • 如果两个操作数都是字符串,则将两个字符串拼接起来;
  • 如果只有一个操作符是字符串,则两另一个操作符转换为字符串(toString),然后再将两个字符串拼接起来。

前面两条规则都非常简单,不会有混淆。对于其他情况,我总结了下面两条规则:

  1. 有一个操作数是复杂数据类型(对象,数组) 时,将两个操作数都转换为字符串(ToString)相加。
  2. 有一个操作数是简单数据类型(true/false, null,undefined) 时,同时不存在复杂数据类型和字符串,则将两个操作数都转换成数值(ToNumber)相加。
  3. 另外还有一种特殊情况{} + 头 的相加式,有些浏览器会将{}视为一个块符号,所以不会参与相加,而是把+符号视为转换符(Number)将后面的操作数转换为数值。

注意上面的规则的权重是从上到下的,每执行一步要从第一条规则开始再进行判断。

下面是改规则的一个判断流程图:

roadmap.path

我们来看看这几道题
1.[] + {}
根据规则,[] 和 {} 都是复杂数据类型,满足有一个操作符是复杂数据类型, 所以将两个值都转换为字符串,调用其toString方法,得到:
"" + "[object Object]" = "[object Object]"

2.1+{}
同样满足第三条规则,结果为
"1" + "[object Object]" = "1[object Object]"

3.'1' + false
其中false满足第4条规则,但同时满足第2条规则'1'是字符串,优先处理第2条规则。所以处理结果应该是将false转为字符串
"1" + "false" = "1false"

看看题目中的
{} + []
按规则计算结果应该是
"[object Object]"
但是控制台打印出来的结果却是0,别忘了第5条,当{}+开头的时候,{}并不参与计算,只是被单做一个空的代码块,所以{}+[]实际上是+[], 即Number([]) => Number("") => 0

那么{}+{}就是+{},等于Number({}) => Number("[object Object]") => NaN 然而我们看到结果再次出乎我们的意料,控制台输出的是
"[object Object][object Object]"
到底是怎么回事?

原来对于{}+{}
不同浏览器会有不同的处理结果,在chrome中会输出"[object Object][object Object]",在firefox会输出NaN
这应该是不同浏览器的js引擎解析差异引起的。我们只要记住这个特殊情况就行了。

其实这些特殊值的计算我们平时都很少接触到,也没有多大的意义。关键还是要加深对JS中对数值转换的理解,以不变应万变。到真正遇到问题的时候,不至于摸不着头脑。