JS操作符运算时的类型转换总结

ECMAScript 操作符的与众不同之处在于,它们能够适用于很多值,例如字符串、数字值、布尔值,甚至对象。不过,在应用于对象时,相应的操作符通常都会调用对象的 valueOf() 和(或)toString() 方法,以便取得可以操作的值。

valueOf() 方法

JavaScript调用valueOf方法将对象转换为原始值。你很少需要自己调用valueOf方法;当遇到要预期的原始值的对象时,JavaScript会自动调用它。默认情况下,valueOf方法由Object后面的每个对象继承。 每个内置的核心对象都会覆盖此方法以返回适当的值。如果对象没有原始值,则valueOf将返回对象本身。

JavaScript的许多内置对象都重写了该函数,以实现更适合自身的功能需要。因此,不同类型对象的valueOf()方法的返回值和返回值类型均可能不同。

对象 返回值
Array 返回数组对象本身
Boolean 返回布尔值1
Date 返回时间的毫秒数(从 1970 年 1 月 1 日起计)
Function 返回函数本身
Number 返回数字值
Object 返回对象本身(默认)
String 返回字符串值
Math & Error 没有 valueOf 方法

你可以在自己的代码中使用 valueOf 将内置对象转换为原始值。 创建自定义对象时,可以覆盖 Object.prototype.valueOf() 来调用自定义方法,而不是默认 Object 方法。

操作符

  1. 一元操作符(++/– 和 +/-)

    递增和递减以及一元加和一元减(操作符置于数值前)的转换规则是一致的,但是注意一元加和一元减(操作符置于数值前)的运算对数值不产生任何影响,也就是说等于转换后的原始值的数值大小,而递增和递减需要对数值执行加减 1。接下来介绍它们的规则:

    • 包含有效数字字符的字符串,变量值转数字值,再执行相关操作
    • 不包含有效数字字符的字符串,变量值转 NaN,再执行相关操作
    • 布尔值,变量值转 0 或 1,再执行相关操作
    • 浮点数值,直接执行相关操作
    • 用于对象时,先调用 valueOf() 方法取得对象的原始值,然后对取得的原始值再进行以上 4 步中的规则。如果取得的原始值结果为 NaN,就再调用 toString() 方法后再应用前述规则。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      var s1 = "2";
      var s2 = "a";
      var s3 = false;
      var s4 = 1.1;
      var s5 = {
      valueOf: function() {
      return -1;
      }
      };

      s1++ // 3
      s2++ // NaN
      s3++ // 1
      s4-- // 0.10000000000000009(由于浮点摄入错误导致)
      s5-- // -2

      +s1 // 2
      +s2 // NaN
      -s3 // -0
      -s4 // -1.1
      -s5 // 1
  2. 布尔操作符(!和 && 和 ||)

      • 操作数是对象、非空字符串和任意非 0 数值(包括 Infinite),都返回false
      • 操作数是空字符串、数值 0、null、undefined 和 NaN,都返回 true

        1
        2
        3
        4
        5
        6
        7
        8
        9
        console.log(!{a:1});     // false
        console.log(!"blue"); // false
        console.log(!12345); // false
        console.log(!""); // true
        console.log(!0); // true
        console.log(!null); // true
        console.log(!undefined); // true
        console.log(!false); // true
        console.log(!NaN); // true

    • 在有一个操作数不是布尔值的情况下,逻辑与操作就不一定返回布尔值;此时,它遵循以下规则:

      • 第一个操作数是对象,返回第二个操作数
      • 第二个操作数是对象,则第一个操作数的求值结果为 true 的请款下才会返回该对象
      • 两个操作数都是对象,返回第二个操作数
      • 有一个操作数是 null,则返回 null
      • 有一个操作数是 NaN,则返回 NaN
      • 有一个操作数是 undefined,则返回 undefined
    • 在有一个操作数不是布尔值的情况下,逻辑或操作就不一定返回布尔值;此时,它遵循以下规则:

      • 第一个操作数是对象,返回第一个操作数
      • 第一个操作数求值的结果为 false,则返回第二个操作数
      • 两个操作数都是对象,返回第一个操作数
      • 两个操作数都是 null,则返回 null
      • 两个操作数都是 NaN,则返回 NaN
      • 两个操作数都是 undefined,则返回 undefined
  3. 加性操作符(+ 和 -)

    如果两个操作符都是数值,执行常规的加减法计算,遵循如下规则:

    • 有一个操作数是 NaN,相加和相减结果都为 NaN
    • 两数都为 Infinite,相加结果为 Infinite,相减结果为 NaN
    • 两数都为 -Infinite,相加结果为 -Infinite,相减结果为 NaN
    • 两数分别为 Infinite 和 -Infinite:

      • 相加:结果为 NaN
      • 相减:

        1. Infinite 减 -Infinite,结果为 Infinite
        2. -Infinite 减 Infinite,结果为 -Infinite
    • 两数都为 +0,相加和相减结果都为 +0
    • 两数都为 -0,相加结果为 +0,相减结果为 -0
    • 左右两数分别为 +0 和 -0,相加结果为 +0,相减结果为 -0
    1. 相加

      如果有一个操作数是字符串,按如下规则转换:

      • 另一个操作数也是字符串,执行字符串拼接
      • 另一个操作数不是字符串,将不是字符串的操作数转换为字符串,执行字符串拼接

        如果有一个操作数是对象、数值或者布尔值,则调用它们的 toString() 方法取得相应的字符串值,然后再应用前面关于字符串的规则。undefined 和 null 调用 toString() 方法取得字符串 “undefined” 和 “null”。

    2. 相减

      如果有一个操作数是字符串、布尔值、null 或 undefined,则先调用 Number() 方法将其转换为数值,再根据前面的规则进行减法计算。如果转换的结果是 NaN,则减法的结果就是 NaN

      如果有一个操作数是对象,则调用对象的 valueOf() 方法取得表示该对象的原始值。如果取得 NaN,则减法结果就是 NaN。如果对象没有 valueOf() 方法,则调用其 toString() 方法将得到的字符串转为数值。

  4. 关系操作符(==/!= 和 ===/!==)

    • 相等和不相等

      • 有一个操作数是布尔值,先转换其为数值(0 或 1)再比较
      • 有一个操作数是字符串,另一个是数值,先转换字符串为数值再比较
      • 有一个操作数是对象,另一个操作数不是,则调用对象的 valueOf() 方法,用得到的基本类型值按照前面的规则继续比较
      • null == undefined
      • null 和 undefined 在比较之前不做任何转换
      • 有一个操作数是 NaN,相等比较返回 false,不等比较返回 true
      • 两个操作数都是 NaN,相等比较返回 false(因为按照规则,NaN != NaN)
      • 如果两个操作数都是对象,则比较它们是不是同一个对象(如果两个操作数都指向同一个对象,则相等比较返回 true;否则,返回 false)

        1
        2
        3
        4
        5
        6
        7
        8
        9
        console.log("NaN" == NaN);       // false
        console.log(5 == NaN); // false
        console.log(NaN == NaN); // false
        console.log(NaN != NaN); // true
        console.log(null == undefined); // false
        console.log(null == 0); // false
        console.log(undefined == ""); // false
        console.log(false == null); // false
        console.log(false == undefined); // false
    • 全等和不全等

      全等和不全等只在两个操作数未经转换就相等的情况下返回 true,在这里一定记住:null !== undefined。