先来看一段代码
[]+{} // "[object Object]"{}+[] // 0console.log({}+[]); // "[object Object]"
当你看到下面代码的执行结果时,是不是和我一样的感受😂,希望看完这篇文章能解除你的困惑!

这是为什么?先来试着理解一下下面这两段话
- 复合类型的变量在进行运算时,会先调用自身的 valueOf 方法,如果返回的是基本数据类型,则直接用于计算,如果仍然是复合类型,再调用自身的 toString 方法,返回基本类型则计算,复合类型则报错。
- 如果用于计算的两个变量都为数值类型,则进行相应的数字运算(比如 + - * /),如果是字符串类型的话,则进行字符串拼接。
我们来验证一下上面说对对不对
// 做一个加运算1 + []; // "1"// 输出为字符串 “1”// 先调用 valueOf[].valueOf(); // []// valueOf 返回对是复合类型,所以会继续调用 toString[].toString(); // ""// 所以转换后就等于1 + "";// 我们都知道,一个数字和一个字符串相加,结果会进行拼接,所以最后输出了字符串 "1"// 那么我们怎么证明它是先调用了 valueOf 方法呢?// 我们再来写一段代码var a = [];a.valueOf = () => "xxx";1 + a; // "1xxx"// 这里就证实了是先调用了 valueOf 方法
我们先根据第一点来推理一下上面的代码
[]+{}
[] 是复合类型,所以先调用 valueOf
[].valueOf(); // []
返回的仍然是复合类型,再继续调用 toString 方法
[].toString(); // ""
这次是返回的是基本类型:字符串,然后在对 {} 进行转换
({}).valueOf(); // {}
返回的仍然是复合类型,再继续调用 toString 方法
({}).toString(); // "[object Object]"
最终得到了两个值都为字符串相加,所以最终结果为 “[object Object]”
"" + "[object Object]"; // "[object Object]"
那为什么反过来就是 0 了呢?
{}+[]; // 0
因为 js 编译器会把 {} 解析为一个代码块,它不会参与计算
所以实际上是这样
+[]
当 + 符号前面没有变量时,会当作正负运算值看待,所以是数字之间的转换,所以 [] 会被转换为 number 类型,
同样的 [] 也会先调用 valueOf,如果是基本类型,则实例化一个 Number 类型并返回,如果是复合类型,再调用 toString,如果是基本类型,则实例化一个 Number 类型并返回,如果还是复合类型就会报错。
+[];// +[]// --> +Number("");// --> +0// --> 0
另外,除了 + 运算符,-、*、/ 最终都会将变量转换为 number 类型进行计算(+ 运算符如果遇到字符串会进行字符串拼接)
1 - [];// 1 - []// --> 1 - Number("")// --> 1 - 0// --> 11 * [];// 1 * []// --> 1 * Number("")// --> 1 * 0// --> 0[] / 1;// [] / 1// --> Number("") / 1// --> 0 / 1// --> 0
console.log({}+[]); // "[object Object]"
上面说 {} 会被解析为代码块,那为什么放到 console.log 里结果不是 0 了呢?
因为放到 console.log 里 {} 就会被解析为一个对象,而不是代码块了
{} 之后直接被定义在代码中,且前面没有任何字符时才会被解析为代码块
所以
({}+[])// ({}+[])// --> "[object Object]" + ""// --> "[object Object]"
