先来看一段代码

    1. []+{} // "[object Object]"
    2. {}+[] // 0
    3. console.log({}+[]); // "[object Object]"

    当你看到下面代码的执行结果时,是不是和我一样的感受😂,希望看完这篇文章能解除你的困惑!

    JS 中的  、-、*、/ 都做了什么? - 图1

    这是为什么?先来试着理解一下下面这两段话

    1. 复合类型的变量在进行运算时,会先调用自身的 valueOf 方法,如果返回的是基本数据类型,则直接用于计算,如果仍然是复合类型,再调用自身的 toString 方法,返回基本类型则计算,复合类型则报错。
    2. 如果用于计算的两个变量都为数值类型,则进行相应的数字运算(比如 + - * /),如果是字符串类型的话,则进行字符串拼接。

    我们来验证一下上面说对对不对

    1. // 做一个加运算
    2. 1 + []; // "1"
    3. // 输出为字符串 “1”
    4. // 先调用 valueOf
    5. [].valueOf(); // []
    6. // valueOf 返回对是复合类型,所以会继续调用 toString
    7. [].toString(); // ""
    8. // 所以转换后就等于
    9. 1 + "";
    10. // 我们都知道,一个数字和一个字符串相加,结果会进行拼接,所以最后输出了字符串 "1"
    11. // 那么我们怎么证明它是先调用了 valueOf 方法呢?
    12. // 我们再来写一段代码
    13. var a = [];
    14. a.valueOf = () => "xxx";
    15. 1 + a; // "1xxx"
    16. // 这里就证实了是先调用了 valueOf 方法

    我们先根据第一点来推理一下上面的代码

    1. []+{}
    1. [] 是复合类型,所以先调用 valueOf

      1. [].valueOf(); // []
    2. 返回的仍然是复合类型,再继续调用 toString 方法

      1. [].toString(); // ""
    3. 这次是返回的是基本类型:字符串,然后在对 {} 进行转换

      1. ({}).valueOf(); // {}
    4. 返回的仍然是复合类型,再继续调用 toString 方法

      1. ({}).toString(); // "[object Object]"
    5. 最终得到了两个值都为字符串相加,所以最终结果为 “[object Object]”

      1. "" + "[object Object]"; // "[object Object]"

    那为什么反过来就是 0 了呢?

    1. {}+[]; // 0

    因为 js 编译器会把 {} 解析为一个代码块,它不会参与计算

    所以实际上是这样

    1. +[]

    当 + 符号前面没有变量时,会当作正负运算值看待,所以是数字之间的转换,所以 [] 会被转换为 number 类型,

    同样的 [] 也会先调用 valueOf,如果是基本类型,则实例化一个 Number 类型并返回,如果是复合类型,再调用 toString,如果是基本类型,则实例化一个 Number 类型并返回,如果还是复合类型就会报错。

    1. +[];
    2. // +[]
    3. // --> +Number("");
    4. // --> +0
    5. // --> 0

    另外,除了 + 运算符,-、*、/ 最终都会将变量转换为 number 类型进行计算(+ 运算符如果遇到字符串会进行字符串拼接)

    1. 1 - [];
    2. // 1 - []
    3. // --> 1 - Number("")
    4. // --> 1 - 0
    5. // --> 1
    6. 1 * [];
    7. // 1 * []
    8. // --> 1 * Number("")
    9. // --> 1 * 0
    10. // --> 0
    11. [] / 1;
    12. // [] / 1
    13. // --> Number("") / 1
    14. // --> 0 / 1
    15. // --> 0

    1. console.log({}+[]); // "[object Object]"

    上面说 {} 会被解析为代码块,那为什么放到 console.log 里结果不是 0 了呢?

    因为放到 console.log 里 {} 就会被解析为一个对象,而不是代码块了

    {} 之后直接被定义在代码中,且前面没有任何字符时才会被解析为代码块

    所以

    1. ({}+[])
    2. // ({}+[])
    3. // --> "[object Object]" + ""
    4. // --> "[object Object]"