看到这样一个问题:{} + [] 的结果是多少? 一脸懵逼..
于是在chrome控制台运行 {} + [] 和用 console.log({} + []) 输出,发现结果不一样..
于是,把各种可能的情况都考虑了一下:
//情形一:控制台直接输出 []+[] //"" []+{} //"[object Object]" {}+[] //0 {}+{} //NaN //情形二:括号语句里面输出 ([]+[]); //"" ([]+{}); //"[object Object]" ({}+[]); //"[object Object]" ({}+{}); //"[object Object][object Object]" //情形三:console.log()输出 console.log([]+[]); //空 console.log([]+{}); //[object Object] console.log({}+[]); //[object Object] console.log({}+{}); //[object Object][object Object] //输出结果长度 console.log(([]+[]).length); //0 console.log(([]+{}).length); //15 console.log(({}+[]).length); //15 console.log(({}+{}).length); //30
为什么结果会是这样的呢?被绕晕了。
首先情形二和情形三很简单,情形三就是将情形二中得到的字符串通过console.log()指令输出,最后输出的长度就是情形二中求得的 字符串的长度。
现在重点考虑,情形一和情形二的区别。
加号运算符———值的类型转换原理
Javascrip基本数据类型Undefined
、Null
、Boolean
、Number
和String,引用数据类型Object类型,其中
Object
包括array跟function。
加号运算符能执行三种转换:把值转化成基本数据类型,数字和字符串。
//a、b类型不确定 a+b;
(1)如果a 、b都为基本数据类型,直接按基本类型参与运算
(2)如果a或者b是对象类型,首先调用对象的 valueOf
方法,如果返回一个基本类型,则以该基本类型参与运算;否则调用 toString
方法,返回基本类型则参与运算
一个例外是 Date 的实例,其实例首先调用 toString
,接着才调用 valueOf
。
(3)否则,抛出错误TypeError
回到最开始的问题
(1)数组与数组相加
[]+[] //"" [].valueOf(); //[] [].toString(); //""
数组的 valueOf()方法
返回自身,因此不是基本类型,接着调用 toString()方法
,空数组返回空字符串。 [1,2].toString(); // "1,2"
(2)数组与对象相加
[]+{} //"[object Object]" [].valueOf(); //[] [].toString(); //"" ({}).valueOf(); //object {} ({}).toString(); //"[object Object]"
对象和数组转换原理一样,普通对象的toString()方法始终返回字符串 “[object Object]”,所以有 “”+ “[object Object]”= “[object Object]”。
(3)对象和数组相加、对象和对象相加
{}+[] //0 {}+{} //NaN
发现以上方法在这里行不通了,什么原因呢?
问题在于JavaScript把第一个{},解析成空的代码块并且忽略它了。{}+[] 可以看成 +[] 、{}+{}可以看成+{}。
现在可以明白了,+[] 这里的加号并不是二元元素符的那个加号,而是一元运算符,作用是,把值转换为Number
,跟Number()
方法一样。
Number([]); //0 Number({}); //NaN
//+{} 等价于 Number({}) Number({}.toString()) // {}.valueOf() isn’t primitive Number("[object Object]") NaN
为什么第一个{}会被解析成代码块呢?因为这{}在这个声明的起始,所以被当成复合语句块了。
当{}既可以被理解为复合语句块也可以被理解为对象直接量或函数声明的时候,JavaScript将会将其理解成为复合语句块。
然后,怎么修复呢??
问题引到情形二的情况,括号语句里面输出,即强制解析器把它认为是表达式。 js把()中的语句当做一个表达式 JS高程P185
因此{}不能被理解为语句块,而被理解为"[object Object]" + "",console.log("[object Object]"+"")打印结果为[object Object]。
({}+[]); //"[object Object]" ({}+{}); //"[object Object][object Object]"
参考资料: