要弄明白这个问题首先我们要了解JS中的类型转换以及引用类型的转换,我们通常把值从一种类型转化为另一种类型称为类型转换,这是显示的情况;隐式的情况称为强制类型转换

一、引用类型的转换

在JavaScript中强制类型转换总是返回标量基本类型的值,不会返回对象和函数。

对于对象(包括数组),为了将值转换为相应基本类型的值,抽象操作ToPrimitive会首先检查该值是否有valueOf()方法,如果有并且返回基本类型的值,就使用该方法进行强制类型转换;如果没有就使用toString()发放进行强制类型转换,如果valueof()toString()都不存则会报错。

我们在对象obj1、obj2上面分别定义了 valueOf()toString(),对象先会在自己身上查找这两个方法,如果有则会覆盖原型的方法,如果对象没有这个方法,然后在到原型上查找。

下面这个例子没有定义上面的两个方法,则会调用原型链上的方法。

下面这个例子中我们使用Object.create(null)创建了一个对象,它没有继承任何原型方法,由于它的__proto__undefined,自身也没有定义valueOf()toString()所以在进行强制类型转换的时候会报错。

如果我们给它添加一个valueOf()toString()

二、字符串和数字的隐示强制类型转换

在很多时候我们经常使用+来进行数字加法和字符串拼接。

let a = '12'
let b = '10'
let c = 12
let d = 10
let add1 = a + b // '1210'
let add2 = c + d // 22
复制代码

这里会得到两个不同的结果,原因在于:第一个执行的是字符串拼接的操作,第二个执行的是数字加法操作。

let arr1 = [1,2]
let arr2 = [3,4]
arr1 + arr2 = '1,23,4'
复制代码

因为上上面的数组通过toString()方法也能转换为字符串所以也是执行字符串拼接操作。

在书上这样写道:

如果某个操作数是字符串或则能通过以下操作转换为字符串的话,+将执行字符串拼接操作。如果其中一个操作数是对象(包括数组),则首先对其调用ToPrimitive抽象操作,该抽象操作再调用[[DefaultValue]],以数字作为上下文。

接下来就是讨论我们今天的问题了:{}+[] != []+{}

我们先对[]{}进行单独分析:

[].toString() // ""
+[] // 0 这里先执行toString()转换为"",然后使用 + 执行强制类型转换为 0
{}.toString() // "[object Object]"
+{} // NaN
复制代码
  • []+{}: 这里的加号执行的是字符串拼接的操作,[]和{}分别调用toString()方法,最后就相当于: "" + "[object Object]" 所以最后结果是:"[object Object]"
  • {}+[]: 这里有一点特殊 {}会被看作是一个独立的代码块,相当于:
{
    
}
+[]
复制代码

这里{}代码块不执行任何操作,而且代码块结尾不需要分号,所以也不存在语法上的问题,所以在这里就相当于执行 +[],所以最后结果是0.

最后由于本还在在校学生一名才疏学浅,有什么问题希望大家提出来,希望与大家一起进步。

参考书籍: 你不知道的JavaScript