前端数据类型

436 阅读9分钟

1. 获取数据类型

js中的数据类型

  1. 原始类型:String,Number, Boolean,null, undefined, BigInt,Symbol

  2. 对象类型: Object

    包括很多通过 new keyword 创建的数据,比如 new Object,new Array,new Map,new Set

获取类型的方法

  • typeof
  • instanceof
  • constructor(慎用)
  • Object.prototype.toString(推荐)
  1. typeof :7 种原始类型,使用 typeof 运算符检查

    console.log('string',typeof '')
    console.log('number',typeof 123)
    console.log('boolean',typeof false)
    console.log('undefined',typeof undefined)
    console.log('bigint',typeof BigInt(123))
    console.log('symbol',typeof Symbol())
    console.log('null',typeof null) //异常:打印结果是object
    
  2. instanceof: 检查 Object 数据类型。构造函数推荐使用instanceof检测。

    function Person() {};
    const a = new Person();
    
    // 判断Object.prototype是否在a的原型链上
    a instanceof Object // true 
    a instanceof Person // true
    
  3. constructor: 检测某个实例属否属于这个类的

    1. 语法:实例.constructor === 类

    2. 返回值:属于返回TRUE,不属于返回FALSE

      [1,2,3].constructor === Array; // true
      
    3. 弊端:容易被篡改

      Array.prototype.constructor = {};
      const arr = new Array(1,2,3);
      arr.constructor === Array; // false
      
  4. Object.prototype.toString(推荐)

    对于 Object.prototype.toString() 方法,会返回一个形如 "[object type]" 的字符串。

    如果此数据类型的 toString() 方法未被重写,就会返回如上面形式的字符串。

    ({}).toString();     // => "[object Object]"
    Math.toString();     // => "[object Math]"
    

    但是,大多数数据类型,toString() 方法都是重写了的,如下:

    console.log('boolean', (false).toString()); //boolean 'false'
    console.log('number', (123).toString()); //number '123'
    

    需要用 call方法来调用。

    console.log('string',Object.prototype.toString.call(''));
    console.log('number',Object.prototype.toString.call(123));
    console.log('boolean',Object.prototype.toString.call(false));
    console.log('undefined',Object.prototype.toString.call(undefined));
    console.log('bigint',Object.prototype.toString.call(BigInt(123)));
    console.log('symbol',Object.prototype.toString.call(Symbol()));
    console.log('null',Object.prototype.toString.call(null));
    console.log('object',Object.prototype.toString.call({}));
    

2.类型转换

指将数据从一种类型转换到另一种类型的过程。类型转换分为两类:

  • 显式的类型转换:就是你可以在代码中看到的类型由一种转换到另一种,比如Number(值)、String(值)...
  • 隐式的类型转换:多是某些其他运算可能存在的隐式副作用而引发的类型转换。比如 +-...

2.1 显式类型转换

  • 常用的显式类型转换方法有 StringtoStringBooleanNumberparseIntparseFloat 等等

2.2 隐式类型转换

  • 隐式转换的场景:

    1. 算术运算
    2. 单目运算符+
    3. if条件表达式转换为布尔
    4. !运算符转为布尔
    5. ==比较
    6. 比较运算符>、<、≥、≤
  • == 隐式转换规则

    == 和 === 的区别在于,粗略相等 检查的是允许类型转换情况下的值的相等性,而 严格相等 检查不允许类型转换情况下的值的相等性;

    • 字符串和数字比较, 会把字符串转换成数字
    • 有布尔值的, 把布尔值转换成数字
    • 对象和标准基本类型之间的相等比较, 调用对象的toPrimitive
    • 在 == 中,undefined == undefined或者null,不等于其他任何值,null同理;
    • NaN不等于任何值包括NaN
      NaN === NaN // false;
      
      NaN 是唯一一个不等于自身的值,所以会用 值 !== 值 来判断isNaN

2.3 类型转换

类型转换中主要涉及到四种转换:

  1. 将值转为数字,ToNumber()。
  2. 将值转为字符串,ToString()。
  3. 将值转为布尔值,ToBoolean()
  4. 将值(复杂类型)转为原始值,Symbol.toPrimitive()。

2.3.1 ToString

通过ToString将值转换为字符串

  • 根据参数类型进行下面转换:

    参数结果
    undefined'undefined'
    null'null'
    布尔值转换为'true' 或 'false'
    数字数字转换字符串,比如:1.765转为'1.765'
    字符串无需转换
    对象先进行 ToPrimitive(obj, String)转换得到原始值,在进行ToString转换为字符串
    //----------- 运算
    // 1. 加法运算符 
    console.log(false + '123')
    
    //----------- ==
    // 2. == !object(非对象) && !number(非数字) && !boolean(非布尔类型)
    console.log('abc' == null)
    console.log('abc' == undefined)
    // 3. == object
    console.log('123' == [123]) 
    1、由于[123]是对象类型,故先进行原始类型转换,ToPrimitive(input, String)运算。
    2、继续执行toString方法,[123].toString(),返回"123",是原始值。
    3、转换为原始值后再进行toString运算,"123" 就转换为 '123'4、故最终的结果为 '123' == '123' //true
    

2.3.2 ToNumber

  • 根据参数类型进行下面转换:

    参数结果
    undefinedNaN
    null0
    布尔值true转换1,false转换为0
    数字无需转换
    字符串有字符串解析为数字,例如:‘324’转换为324,‘qwer’转换为NaN, ''转化为数字0
    对象先进行 ToPrimitive(obj, Number)转换得到原始值,在进行ToNumber转换为数字
    //---------- 运算
    // 1. - / *
    console.log(123 / '123')
    console.log(123 - '123')
    console.log(123 * '123')
    // 2. + !string(非字符串)
    console.log(123 + false)
    console.log(123 + null)
    
    //---------- ==
    // 3. == !object(非对象)
    console.log(123 == false)
    // 4. == object
    console.log(123 == [123]) 
    1、由于[123]是对象类型,故先进行原始类型转换,ToPrimitive(input, Number)运算。
    2、所以会执行valueOf方法,[123].valueOf(),返回的还是[123]对象,不是原始值。
    3、继续执行toString方法,[123].toString(),返回"123",是原始值。123
    4、转换为原始值后再进行ToNumber运算,"123" 就转换为 1235、故最终的结果为 123 === 123 
    

2.3.3 ToBoolean

参数结果
undefinedfalse
nullfalse
布尔值无需转换
数字0、-0、NaN为false,其他的为true
字符串'' 为false,其他为true
对象true

2.3.4、通过ToPrimitive将对象转换为原始值

  • Symbol.toPrimitive(input, PreferredType?)

    • input是要转换的值
    • PreferredType是可选参数,可以是Number或String类型。
    1. 如果有Symbol.toPrimitive()方法,优先调用并返回
    var obj = {
        [Symbol.toPrimitive] () {
              return 3;
        },
        valueOf () {
              return 2;
        },
        toString () {
              return 1;
        }
    }
    
    // obj == 3 true
    
    2. 如果没有Symbol.toPrimitive()方法,PreferredType被标记为Number,则会进行下面的操作流程来转换输入的值。
    1、如果输入的值已经是一个原始值,则直接返回它
    2、否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,如果valueOf()方法的返回值是一个原始值,则返回这个原始值。
    3、否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
    4、否则,抛出TypeError异常。
    
    3. 如果没有Symbol.toPrimitive()方法,PreferredType被标记为String,则会进行下面的操作流程来转换输入的值。
    1、如果输入的值已经是一个原始值,则直接返回它
    2、否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
    3、否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,如果valueOf()方法的返回值是一个原始值,则返回这个原始值。
    4、否则,抛出TypeError异常。
    
    4. 如果没有Symbol.toPrimitive()方法,省略preferedType
    1、该对象为Date类型,则PreferredType被设置为String
    2、否则,PreferredType被设置为Number



    

    valueOf方法和toString方法解析

    • Object.prototype是所有对象原型链顶层原型,所有对象都会继承该原型的方法,故任何对象都会有valueOf和toString方法。

    1. valueOf

      1. Number、Boolean、String这三种构造函数生成的基础值的对象形式,通过valueOf转换后会变成相应的原始值。如:

        var num = new Number('123');
        num.valueOf(); // 123
        
        var str = new String('12df');
        str.valueOf(); // '12df'
        
        var bool = new Boolean('fd');
        bool.valueOf(); // true



        
      2. Date这种特殊的对象,其原型Date.prototype上内置的valueOf函数将日期转换为日期的毫秒的形式的数值。

         var a = new Date();
        a.valueOf(); // 1515143895500
        
      3. 除此之外返回的都为this,即对象本身:

        var a = new Array();
        a.valueOf() === a; // true
        
        var b = new Object({});
        b.valueOf() === b; // true
    2. toString

      Number、Boolean、String、Array、Date、RegExp、Function这几种构造函数生成的对象,通过toString转换后会变成相应的字符串的形式,因为这些构造函数上封装了自己的toString方法。如:

      var num = new Number('123sd'); 
      num.toString(); // 'NaN'
      
      var str = new String('12df');
      str.toString(); // '12df'
      
      var bool = new Boolean('fd');
      bool.toString(); // 'true'
      
      var d = new Date();
      d.toString(); // "Wed Oct 11 2017 08:00:00 GMT+0800 (中国标准时间)"
      
      var func = function () {}
      func.toString(); // "function () {}"
      

      Array转换(⚠注意)

      var arr = [1,2]; 
      arr.toString(); // '1,2'
      

      除这些对象及其实例化对象之外,其他对象返回的都是该对象的类型,都是继承的Object.prototype.toString方法。

      var obj = new Object({});
      obj.toString(); // "[object Object]"
      
      Math.toString(); // "[object Math]"
      
      

1.4 常见变量转换表

原始值转为数字转为字符串转为布尔
false0"false"false
true1"true"true
00"0"false
11"1"true
"0"0"0"true
"000"0"000"true
"1"1"1"true
NaNNaN"NaN"false
InfinityInfinity"Infinity"true
-Infinity-Infinity"-Infinity"true
""0""false
"20"20"20"true
"a"NaN"a"true
[]0""true
[10,20]NaN"10,20"true
function(){}NaN"function(){}"true
{ }NaN"[object Object]"true
null0"null"false
undefinedNaN"undefined"false

1.5 实践

  1. 对象和数字/布尔值比较

    对象和布尔值进行比较时,对象先ToPrimitive(input, Number)运算,然后再转换为数字,布尔值直接转换为数字

    {} == 1;
    1、由于{}是对象类型,故先进行原始类型转换,ToPrimitive(input, Number)运算。
    2、所以会执行valueOf方法,({}).valueOf(),返回的还是{}对象,不是原始值。
    3、继续执行toString方法,({}).toString(),返回"[object Object]",是原始值。
    4、转换为原始值后再进行ToNumber运算,"[object Object]"就转换为NaN5true转换为数字1。
    故最终的结果为 NaN == 1
    
    [] == 0; 
    1、由于[]是对象类型,故先进行原始类型转换,ToPrimitive(input, Number)运算。
    2、所以会执行valueOf方法,([]).valueOf(),返回的还是[]对象,不是原始值。
    3、继续执行toString方法,([]).toString(),返回"",是原始值。 // 数组中的toString()方法会被改写
    4、转换为原始值后再进行ToNumber运算,""就转换为05、故最终的结果为 0 == 0
    
  2. 对象和字符串比较

    对象和字符串进行比较时,对象先ToPrimitive(input, Number)运算,然后再转换为字符串,然后两者进行比较。

    [1,2,3] == '1,2,3' 
    1、由于[]是对象类型,故先进行原始类型转换,ToPrimitive(input, String)运算。
    3、继续执行toString方法,([]).toString(),返回"1,2,3",是原始值。 // 数组中的toString()方法会被改写 
    4、转换为原始值后再进行ToString运算,"1,2,3"就转换为"1,2,3"。
    故最终的结果为 '1,2,3' == '1,2,3' 
    
  3. 字符串和 数字 比较

    字符串和数字进行比较时,字符串转换成数字,二者再比较。

    '1' == 1 // true
    
  4. 字符串和布尔值 比较

    字符串和布尔值进行比较时,二者全部转换成数值再比较

    '1' == true; // true 
    
  5. 布尔值和数字比较

    布尔值和数字比较时, 布尔转为数字, 二者比较

    true == 1 // true