js数据类型自动转化规律

1. 原始数据遇运算符

1. +运算符

1) 如果算子两侧都是字符串,返回拼接结果;

2) 如果算子两侧不全是字符串,则根据实际情况:

  • 如果需要字符串,就调用String();
true + "1"; // "true1"
  • 如果需要数字转为数字,就调用Number();
true + 1; //2
  • 如果都可以,优先转为数字。
true + true; //2

2. -*/减法、乘法、除法运算符

所有的算子全部转为数字,使用Number()/+。

'4' - '5'; // -1
4-'5'; //-1
true - false; // 1
'4'/'5'; 0.8

3.非相等比较运算符

>,>=,<,<=

1)如果算子两侧都是字符串,按照Unicode码点依次比较大小

2)如果算子两侧不全是字符串,转为数字进行比较(Number()/+)。

true < '8'; // true
'7' < 8; // true

4.相等比较运算符(==)

1) 如果是不同原始类型的值,将字符串和布尔值都转为数字(Number()或者+)。

true == '1'; //true 
'true' == true; // false Number('true')->NaN
// NaN用于任何运算符返回值都是false

2)如果其中一方是对象,先将其转为原始类型的值

    如果两侧都是对象,则永远不相等。

3) null == undefined

4)null和undefined都不等于其他值

null == 0; //false
undefined == 0; //false

4) NaN 和任何值都不相等

5.严格相等运算符(===)

1)如果类型不相同,直接返回false

2)如果类型相等,值也相同,直接返回true

2. 对象遇到运算符

1.+运算符

最终结果是对象需要转化成原始数据。

1)对象首先调用valueOf()方法,如果不自定义,一般都返回自身;

2)再调用toString()方法,返回对应的字符串。

但是,Date对象不同,是先调用toString(), 后调用valueOf()

var arr = [5];
arr + 1;//  "51"
var obj = {
    toString() { return "hello"},
    valueOf() {return 1}
};
obj + "2"; // "12"  不管另一个算子是什么类型,都是先调用valueOf()
var date = new Date();
date.toString = function(){return "hello"};
date.valueOf = function(){return 1};
date + 1; // "hello1" 不管另一个算子什么类型,都是先调用toString()

2. -*/减法、乘法、除法运算符

和直接调用Number()一样; 

Date对象和其他对象一样,遵循Number()函数的调用规则;

var obj = {
    valueOf(){return "8"},
    toString() {return "9"}
}
obj - 8; // 0
var date = new Date();
date.valueOf = function(){return "8"};
date.toString = function(){return "9"};
date - 8; // 0

3.非相等比较运算符

规则和+运算符(Number()工具函数)一致。 

1)先调用valueOf()方法,如果返回值不是原始值,再调用toString()方法

2)调用toString()后还不是原始值,返回NaN

Date对象和其他对象一样,遵循上面的规则!

var obj = {
    valueOf(){return "8"},
    toString() {return "9"}
}
obj > 8; // false
var date = new Date();
date.valueOf = function(){return "8"};
date.toString = function(){return "9"};
date > 8; // false

4. 相等运算符(==)

如果运算符两侧都是对象,除非地址相同,否则返回都是false;

如果比较符一侧是原始类型的值:

1)先调用valueOf(),如果返回不是原始类型的值,再调用toString();

2) 如果toString()的值返回的还不是原始类型,返回NaN

Date类型相反,先调用toString();

var obj = {
    valueOf(){return "8"},
    toString() {return "9"}
}
obj == 8; // true
var date = new Date();
date.valueOf = function(){return "8"};
date.toString = function(){return "9"};
date ==  8; // false

应用:

若使得下面条件成立,a应该使什么值?

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <script type="noscript">
    a什么情况下,使得下面的条件成立
    if(a == 1 && a ==2 && a ==3) {
      console.log(1);
    }
  </script>
  <script>
    //有两类解决方案:1)数据拦截 2)类型转换 
    /**
     * 1)数据拦截
     * a本身可以看作window,使用Object.defineProperty
     */
    var i = 1;
    Object.defineProperty(window, 'a', {
      get() {
        return i++;
      }
    })
    /**
     * 2)类型转换
     *   >  使用==时,如果是对象,会先转成原始类型的值
     *      先调用valueOf(),如果是原始类型的值返回;
     *      否则再调用toString()
     */
    // 1)重写valueOf方法
    var a = {
      index: 1,
      valueOf() {
        return this.index++;
      }
    }
    // 2)重写toString方法
    var a = {
      index: 1,
      toString() {
        return this.index++;
      }
    }
    /* 
     * >  使用==时,如果是对象,会先转成原始类型的值
     *    对象转原型类型本质上是调用的[Symbol.toPrimitive]方法
     *    该方法被调用时,会传入一个参数,表示其转为的预期类型
     *    default/number/string中的一个
    */
    var a = {
      index: 1,
      [Symbol.toPrimitive](hint) {
        // 预期是number/string都可以
        if(hint === 'default') {
          return this.index++;
        }
      }
    }


    // 运行
    if(a == 1 && a ==2 && a ==3) {
      console.log(1);
    }
  </script>
</body>
</html>
View Code

5. 严格相等运算符(===)

如果比较符两侧都是对象,除非地址相同,否则都是false;

var obj1 = {};
var obj2 = obj1;
obj1 === obj2;  // true
var obj3 = {};
obj1 === obj3; //false

如果比较符一侧是原始值,直接返回false

3. String()工具函数遇对象

转化规律:

1)先调用toString(),如果返回原始类型的值,对这个值使用String()方法,结束;如果是对象,继续执行;

2)调用原对象的valueOf()方法,如果返回的是原始类型的值,对这个值使用String()方法,结束;

3)如果上面的步骤执行完成后还是不是原始值,报错!

var obj = {
    valueOf(){ return 5; },    
    toString() { return 'hello'; }
};
String(obj); // "hello"
// 当执行完都不返回原始值时
var obj = {
  valueOf: function () { return {};},
  toString: function () { return {};}
};
String(obj); //Uncaught SyntaxError: Invalid or unexpected token

4. Number()工具函数遇对象

转化规律:

1)先调用valueOf()方法,如果返回原始值,对这个值使用Number()函数,结束;否则继续

2)调用原对象toString()方法,如果返回原始值,对这个值使用Number()函数,结束;

3)如果都不是原始值,报错

var obj = {
    valueOf(){ return 5; },    
    toString() { return 'hello'; }
};
Number(obj); // 5
// 当执行完都不返回原始值时
var obj = {
  valueOf: function () { return {};},
  toString: function () { return {};}
};
Number(obj); //Uncaught SyntaxError: Invalid or unexpected token

 5. 当遇到函数时

当遇到函数调用,就会自动调用函数的toString()方法;

所以执行a();会打印两次2

function a() {
    var obj = function(){

    }; 
    obj.valueOf= function(){console.log(1); },    
    obj.toString = function() {console.log(2);} 
    return obj; // 2
}; 
a(); // 2  
原文地址:https://www.cnblogs.com/lyraLee/p/11627350.html