JS基础知识-数据类型转换

类型转换

  • 显示类型转换:把值从一个类型转成另一种类型
  • 强制类型转换:会在内部进行一些内置的操作,转换为目标类型
valueOf():将(内置)对象转换为原始值
对象 返回值
Array 返回数组对象本身
Boolean 布尔值
String 字符串值
Number 数字值
Date 存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC
Function 函数本身
Object 对象本身。这是默认情况
Math 和 Error 对象 没有 valueOf 方法
  • Array:返回数组对象本身
    var array = ["emoji", true, 12, -5];
    console.log(array.valueOf());    // ["emoji", true, 12, -5]
    console.log(array.valueOf() === array);    // true
    
  • Date:返回当前时间距1970年1月1日午夜的毫秒数
    var date = new Date(2013, 7, 18, 23, 11, 59, 230);
    console.log(date.valueOf());   // 1376838719230
    
  • Number:返回数字值
    var num =  15.26540;
    console.log(num.valueOf());   // 15.2654
    
  • Boolean:返回布尔值true或false
    var bool = true;
    console.log(bool.valueOf() === bool);   // true
    
    // new一个Boolean对象
    var newBool = new Boolean(true);
    // valueOf()返回的是true,两者的值相等
    console.log(newBool.valueOf() == newBool);   // true
    // 但是不全等,两者类型不相等,前者是boolean类型,后者是object类型
    console.log(newBool.valueOf() === newBool);   // false
    
  • Function:返回函数本身
    function foo(){}
    console.log( foo.valueOf() === foo );   // true
    
    var foo2 =  new Function("x", "y", "return x + y;");
    console.log( foo2.valueOf() );
    /*
    ƒ anonymous(x,y) {
        return x + y;
    }
    */
    
  • Object:返回对象本身
    var obj = {name: "张三", age: 18};
    console.log( obj.valueOf() === obj );   // true
    
  • String:返回字符串值
    var str = "http://www.xyz.com";
    console.log( str.valueOf() === str );   // true
    
    // new一个字符串对象
    var str2 = new String("http://www.xyz.com");
    // 两者的值相等,但不全等,因为类型不同,前者为string类型,后者为object类型
    console.log( str2.valueOf() === str2 );   // false
    

总结: 基本数据类型的valueOf返回的是自身的原始类型值,而对象都返回自身,Date返回时间戳,nullundefined没有valueOf方法

toString():返回这个对象的字符串表示
  • 每个对象都有toString()方法,如果自定义对象没有重写该方法,toString会返回[object type],type是对象的数据类型
       var o = new Object();
       o.toString();    // "[object Object]"
    
  1. 可以使用toString()来检测对象的类型:
    每个对象都能通过Object.prototype.toString()来检测的前提是需要用Function.prototye.call()/apply()的形式来调用toString()
    Object.prototype.toString.call(thisArg); // 参数:需要检查的对象

     var toString = Object.prototype.toString;
     Object.prototype.toString.call(null)    // "[object Null]"
     Object.prototype.toString.call(undefined)    // "[object Undefined]"
     Object.prototype.toString.call(new Date)    // "[object Date]"
     Object.prototype.toString.call(Math)    // "[object Math]"
     Object.prototype.toString.call(new String)    // "[object String]"
     Object.prototype.toString.call(new Object)    // "[object Object]" 
    
类型转换只有三中情况:转成布尔值、转成字符串、转成数值
  • 内部转换过程 — 检测类型的四个js内部方法:对象转换类型的时候,会调用内置的[[ToPrimitive]]函数获取[[DefaultValue]],下面是内置函数的具体流程:
  1. ToPrimitive(input[,PreferedType])
    参数input:是输入的值
    参数PreferedType:是转换的目标类型
    • 转换的目标类型是Number
      1. 如果输入的值已经是原始类型,那就不需要转换,直接返回这个值;
      2. 如果输入的值是对象,调用input.valueOf()获取(内置)对象的原始值,是基本数据类型就返回这个值;
      3. 如果上一步获取不到原始类型值,调用input.toString()获取,如果转换为基础类型,就返回转换的值
      4. 如果都没有返回原始类型,就报错
    • 转换的目标类型是String
      第二第三步交换,先执行toString()
      也可以省略preferedType(转换的目标类型),此时,日期会被认为是字符串,而其他的值会被当做Number
  2. ToString(argument)(Object.prototype.toString())
对象 返回值
Null Return 'null'
Undefined Return 'undefined'
Boolean 如果 argument 为 true, return 'true'. 如果 argument 为 false, return 'false'
String Return argument
Number 将数值用字符串表示
Date 用字符串表示
Object 先primValue = ToPrimitive(argument, Number),再对primValue 使用 ToString(primValue)
  • 对普通对象来说,除非自定义重写toString方法,否则都返回内部属性[[class]]的值, 如"[object object]"
  • 就是如果对象有自己的toString()方法,字符串化的时候会先调用自己的方法
  • 类型转换的时候是通过什么来实现的(类型转换内部实现):
    数组的默认toString()方法是进行过重写的,所以数组转换为字符串时的返回与对象不同
var a = [1, 2, 3];

a.toString();    // "1,2,3"

将值转换为相应的基本类型值,抽象操作ToPrimitive会首先检查该值是否有valueOf()方法,如果有并且返回基本类型值,就使用该值强制类型转换,如果没有就使用toString()的返回值来进行强制类型转换

  1. ToNumber(argument):

    对象 返回值
    Null Return 0
    Undefined Return NaN
    Boolean 如果 argument 为 true, return 1. 如果 argument 为 false, return +0
    String 将字符串中的内容转化为数字(比如"23"->23),如果转化失败则返回NaN(比如"23a"->NaN)
    Number Return argument
    Date 返回时间戳
    Object 先primValue = ToPrimitive(argument, Number),再对primValue 使用 ToNumber(primValue)
  2. ToBoolean():

    • 假值有:undefinednullfalse0NaN""
      除了上面的假值,其他都是真值
        // 通过document.all强制类型转换为布尔值来判断浏览器是否是老版本ie
        Boolean(document.all);    // false
        Boolean(window.name);    // false
    
    1. 假值对象:
      浏览器在某些特定情况下,在常规js语法基础上自己创建了一些外来值,相当与不是统一规范都有的属性,是每个浏览器特有的属性,像document.location大家都一样,将他们强制类型转换为布尔值,结果返回false
    2. 封装了假值的对象:
        // 封装了假值的对象
        var a = new Boolean(false);    // Boolean {false}
        var b = new Boolean(0);    // Boolean {false}
        var c = new Boolean("");    // Boolean {false}
        
        var d = a && b && c;    // Boolean {false}
        var e = Boolean(a && b && c);    // true
    
  • 为什么使用e返回true,而不是false?
    因为abc返回的都是对象object,是一个真值
    1. 字符串和数字之间的转换
      通过原生构造函数:String()Number()
    2. 获取时间戳:
      `var timestamp = +new Date();`
      // 方法获取 推荐获取指定时间的时间戳
      `var timestamp = new Date().getTime();`
      // 静态方法获取 推荐使用
      `var timestamp = Date.now();````
      
    3. ~
      ~x大致等同于-(x+1)
      一般我们判断字符串的位置,检查字符串中是否包含指定的字符串用indexOf(),它返回字符串所在的位置,不存在就返回-1,我们会用if条件来判断是否满足我们需要的条件,但是这样的写法不是很好,代码中暴露了底层实现细节,指indexOf底层查找失败就返回-1这种,这些细节我们在写代码的时候应该被屏蔽掉;
      var a = "Hello world";
      if(a.indexOf("lo") >= 0){    // true
          // 找到匹配
      }
      if(a.indexOf("lo") == -1){    // true
          // 没有找到匹配
      }
      
      ~搭配indexOf可以将indexOf查找的结果强制类型转换为真或者假值
      可以使用这种方式来判断,更简洁:
      var a = "Hello world";
      if(~a.indexOf("lo")){    // -4 true
          // 找到匹配
      }
      
      ~a.indexOf("ol");    // 0  是一个假值
      
    4. 字位截除
      Math.floor(-49.6);    // -50
      ~~-49.6    // -49
      -49.6 | 0。  // -49
      ~~x 、 x | 0 都可以把值截除成一个整数(32位整数)
      
    5. 显示解析数字字符串
      解析和转换:
          var a = "42";
          var b = "42px";
          Number(a);    // 42
          Number(b);    // NaN
          parseInt(a);    // 42 默认转换为10进制数,如果要在es5之前环境,要设置第二个参数为10
          parseInt(b);    // 42
      
      解析:从左到右解析,如有非数字的字符就停止返回数字部分
      转换:不允许有非数字的字符,会转换失败返回NaN(转换就是原生构造函数不带new的那些)
      • parseInt(1/0, 19); // 18
        parseInt的第一个参数是字符串,会先将参数转为字符串
      1. 先将参数:1/0转换为字符串((1/0).toString())"Infinity"
      2. 19是基数,parseInt("Infinity", 19)第一个字符I以19为基数时,值为18,第二个n不是游戏啊的数字字符串,所以解析到n就结束了
      0 1 2 3 4 5 6 7 8 9 a:10 b:11 c:12 d:13 e:14 f:15 g:16 h:17 i:18
      parseInt( 0.000008 );// 0 0来自于 "0.000008"
      parseInt( 0.0000008 );// 8 8来自于 8e-7 e不是数字就结束
      
      • JS在处理数值的时候,如果数值小数位数超过6位,就会转换为科学计数法,整数的多于21位也会转为科学计数法
      parseInt( false, 16 );// 250 "fa" 来自于 "false"
      fa的16进制转为十进制 a*16^0 + f*16^1 = 250
      parseInt( parseInt, 16 );// 15 "f" 来自于 "function.."       parseInt( "0x10" );// 16
      0x是16进制的表示,16进制的10转为十进制 0*16^0 + 1*16^1 = 16
      parseInt( "103", 2 );// 2
      按2进制为基础解析字符串“103”,2进制只有0和1,返回10,转为10进制 0*2^0 + 1*2^1 = 2
      
    6. 隐式强制类型转换:
      减少冗余,让代码更简洁
      什么时候代表相加,什么时候是进行字符串拼接,为什么下面是这样的结果:
      var a = [1,2];
      var b = [3,4];
      
      a + b; // "1,23,4"
      
      因为数组的valueOf()操作无法得到简单基本类型值,于是它转而调用 toString()。因此上例中的两 个数组变成了 "1,2""3,4"+将它们拼接后返回"1,23,4"
      如果+的其中一个操作数是字符串或者是通过valueOf或者toString能得到字符串,就进行拼接,不然就相加
      需要注意:'a'++'b' // "aNaN" +'b' 获取number类型 ->NaN
      • 它们返回不同结果:
        []+{} -> ""+{} -> "[object Object]"
        {}+[] -> 0 // 有的js解释器会将开头的 {} 看作一个代码块,而不是一个js对象,于是真正参与运算的是+[],就是将[]转换为number,于是得出答案0
      • 数字强制类型转换为字符串:
      var a = 42;
      var b = a + "";
      b;  // "42"
      
      a + ""(隐式)和前面的String(a)(显式)之间有一个细微的差别需要注意。根据ToPrimitive抽象操作规则,a + ""会对a调用valueOf()方法,然后通过ToString抽象操作将返回值转换为字符串。而String(a)则是直接调用 ToString()
      • 字符串强制类型转换为数字:
      var a = "3.14";
      var b = a - 0;
      b; // 3.14
      
      var a = [3];
      var b = [1];
      a - b; // 2
      
      ab都需要被转换为数字,它们首先被转换为字符串(通过ToString()),然后再转换为数字。
      • 隐式强制类型转换为布尔值:
        1. if (..)语句中的条件判断表达式。
        2. for ( .. ; .. ; .. )语句中的条件判断表达式(第二个)。
        3. while (..)do..while(..)循环中的条件判断表达式。
        4. ? :中的条件判断表达式。
        5. 逻辑运算符||(逻辑或)和 &&(逻辑与)左边的操作数(作为条件判断表达式)。
        以上情况中,非布尔值会被隐式强制类型转换为布尔值,遵循前面介绍过的 ToBoolean 抽象操作规则。

        • || 和 &&
          返回操作数中的一个值,根据这个值来判断真假
        var a = 42;
        var b = "abc";
        var c = null;
        a || b;    // 42
        a && b;    // "abc"
        c || b;    // "abc"
        c && b;    // null
        
        1. 首先判断第一个操作数,不是布尔值进行ToBoolean转换再判断
        2. 判断第一个操作数结果为true||返回第一个操作数,false返回第二个操作数(有一个真就真)
        3. 判断第一个操作数结果为true&& 返回第二个操作数,false返回第一个操作数(有一个假为假)
        • ==允许在相等比较中进行强制类型转换,而===不允许
          就是在判断的时候,宽松相等和严格相等都会检查操作数的类型,就是处理方式不一样,==会进行类型转换
        • 字符串和数字之间的相等比较:
        var a = 42;
        var b = "42";
        a === b;    // false
        a == b;    // true
        

        这里会有疑问,是把数值转为字符串,还是把字符串转为数值进行比较呢?具体内部转换规则:转为数字来比较!
        (1) 如果 Type(x) 是数字,Type(y) 是字符串,则返回 x == ToNumber(y)的结果。
        (2) 如果 Type(x) 是字符串,Type(y) 是数字,则返回 ToNumber(x) == y 的结果。

        • 布尔值和其他类型之间的比较
        var a = "42";
        var b = true;
        a == b; // false
        

        将是布尔值的转为数值来比较;
        (1) 如果 Type(x) 是布尔类型,则返回 ToNumber(x) == y 的结果;
        (2) 如果 Type(y) 是布尔类型,则返回 x == ToNumber(y) 的结果。
        ===不允许强制类型转换,不涉及ToNumber

        • 对象与非对象之间的比较
        var a = 42;
        var b = [ 42 ];
        a == b; // true
        

        (1) 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPrimitive(y) 的结果;
        (2) 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x) == y 的结果。

        • 假值相等比较:
          有一个为null或者undefined, return false;
          有一个为NaN, return false;
          有布尔值Boolean、字符串String、数字Number类型不一致的,都转成Number再比较
          有对象的,转换为原始值再比较(先调用ToPrimitive)
        "0" == null;    // false
        "0" == undefined;    // false
        "0" == false;    // true
        "0" == NaN;    // false
        "0" == 0;    // true
        "0" == "";    // true
        false == null;    // false
        false == undefined;    // false
        false == NaN;    // false
        false == 0;    // true   Number(false) -> 0
        false == "";    // true
        false == [];    // true
        false == {};    // false   Number({}) ->NaN
        "" == null;    // false
        "" == undefined;    // false   Number(undefined) ->NaN
        "" == NaN;    // false
        "" == 0;    // true
        "" == [];    // true
        "" == {};    // false
        0 == null;    // false
        0 == undefined;    // false
        0 == NaN;    // false
        0 == [];    // true
        0 == {};    // false
        [] == ![];    // true   ![] ->false
        2 == [2];    // true
        "" == [null];    // true    
        0 == "\n";    // true   空字符串被ToNumber强制转为0
        "true" == true;    // false Number("true") ->NaN
        
        • 抽象关系比较< >
          如果是对象,先调用ToPrimitive
          如果有一个是非字符串,就把字符串转成数字比较
          如果两个都是字符串就按字符顺序来比较
            var a = [ "42" ];
            var b = [ "043" ];
            a < b; // false
            
            var a = { b: 42 };    "[object, object]"
            var b = { b: 43 };
            a < b; // false
        

        <=表示不大于的意思 >= 不小于的意思

         var a = { b: 42 };
         var b = { b: 43 };
         a <= b; // true b < a ->反转结果false ->true
         a >= b; // true b < a ->反转结果false ->true
        

你可能感兴趣的:(JS基础知识-数据类型转换)