美文网首页程序员JavaScript 进阶营
Javascript知识整理——强制类型转换

Javascript知识整理——强制类型转换

作者: 俗三疯 | 来源:发表于2017-09-07 09:22 被阅读57次

    值类型转换

    将值从一种类型转换为另一种类型通常称为类型转换,这是显式的情况;隐式的情况称为强制类型转换

    类型转换发生在静态类型语言的编译阶段,而强制类型转换则发生在动态类型语言的运行时

    ToString

    字符串化规则
    • null转换为"null"
    • undefined转换为"undefined"
    • true转换为"true"
    • 数字的字符串化则遵循通用规则(极大和极小数字使用指数形式)
    • 对于普通对象来说,除非自行定义,否则toString()返回内部属性[[Class]]的值,若有自己的toString()方法,则会调用该方法返回其他值
    • 对数组来说,toString经过重新定义,将所有单元字符串化后再用“,”链接起来
    • JSON.stringify()在将JSON对象序列化时也用到了ToString
      JSON字符串化与toString()的效果基本相同,只不过序列化的结果总是字符串:
       JSON.stringify(42); // "42"
       JSON.stringify("42")//""42""
       JSON.stringify(null)//"null"
       JSON.stringify(true)//"true"
      
    • 所有安全的JSON值都可以用JSON.stringify()字符串化,安全的JSON指能够呈现为有效JSON格式的值
      undefined,function,symbol和包括循环引用的对象都不符合JSON结构标准,无法处理他们
      JSON.stringify()在对象中遇到undefined,function和symbol时会自动将其忽略,在数组中则会返回null。对包含循环引用的对象执行JSON.strigify()会出错
    JSON.stringify(undefined); //undefined
    JSON.stringify(function(){}); //undefined
    JSON.stringify(
        [1,undefined,function(){},4]
    );                          //"[1,null,null,4]"
    
    • 如果对含有非法JSON值的对象做字符串化,或者对象中的某些值无法被序列化时,就需要定义toJSON()方法来返回一个安全的JSON值(这个值会再通过JSON.stringfy()序列化)

    ToNumber

    转化规则
    • true转换为1
    • false转换为0
    • undefined转换为NaN
    • null转化为0
    • 对象(包括数组)首先转换为相应的基本类型值,如果返回的是非数字的基本类型值,在根据上述规则进行强制转换为数字
      为了把值转换为相应的基本类型值,会先检查该对象是否有valueOf()方法,没有就使用toString后的返回值,如果valueOf()和toString()均不返回基本类型值,会产生TypeError错误。
    var c = [4,2];
    console.log(Number(c)); //undefined
    
    var a = {
        valueOf: function () {
            return "42"
        },
        toString: function () {
            return "41"
        }
    
    }
    var b = {
        toString: function () {
            return "41"
        }
    }
    // console.log(Number(b)) //41
    console.log(Number(a))    //42 (valueOf优先调用)
    

    ToBoolean

    假值
    • undefined
    • null
    • false
    • +0,-0和NaN
    • ""
      以上均为假值,假值列表意外的值都应该是真值(未明确定义)。
    假值对象

    假值对象时指在常规Javascript语法基础上自己创建了一些外来的值,强制类型转换为false。(如document.all)
    而封装了假值的对象,并非假值对象,强制类型转换时仍视作一个对象来看,转为true

    var a = new Boolean(false);
    var b = new Number(0);
    var c = new String("");
    console.log(Boolean(a));    //true
    console.log(Boolean(b));    //true
    console.log(Boolean(c));    //true
    
    真值

    假值以外的值
    表示假值的字符串强制类型转化仍视为非空字符串看待,转化为true

    var a = "false"
    var b = "0";
    var c = "''";
    var d = Boolean(a&&b&&c);
    d;              //true
    

    显式强制类型转换

    显式强制类型转化是那些显而易见的类型转换

    字符串和数字之间的显式转换
    • 除String()和Number()外,还有其他方法可以实现字符串和数字之间的显式转换
    var a = 42;
    var b = a.toString();
    //toString()对a不适用,Javascript引擎自动为42创建一个封装对象,然后调用该对象的toString()方法
    var c = "3.14"
    var d = +c;
    b;          //"42"
    d;          //3.14
    
    • 日期显式转换为数字
      var timestamp = +new Date()
    • 暂不研究~运算符
    显式解析数字字符串
    • 解析允许字符串中含有非数字字符,解析按从左到右的顺序,如果遇到非数字字符就停止,而转换不允许出现非数字字符,否则失败返回NaN
    var a = "42"
    var b = "42px"
    Number(a);      //42
    parstInt(a);    //42
    Number(b);      //NaN
    parseInt(b);    //42
    
    • 解析非字符串
      parseInt()先将参数强制类型转换为字符串再进行解析。
    parseInt(1/0,19);  //18
    //转换为字符串后parse("Infinity",19)
    //第一个字符是“I”,以19为基数时值为18,第二个字符不是一个有效的数字字符,解析到此为止。(19为基数时,有效范围为0-9,a-i)
    
    显示转换为布尔值
    • 显示强制类型转换为布尔值最常用的方法是!!,因为第二个!会把结果反转为原值
    var a = "0";
    var b = [];
    var c = {};
    
    var d = "";
    var e = 0;
    var f = null;
    var g;
    
    !!a;    //true
    !!b;    //true
    !!c;    //true
    
    !!d;    //false
    !!e;    //false
    !!f;    //false
    !!g;    //false
    
    

    隐式强制类型转换

    字符串和数字之间的隐式强制类型转换

    +运算符既能用于数字加法,也能用于字符串拼接
    简单来说,如果+的其中一个操作数是字符串(或者可以隐式转换为字符串)则执行字符串拼接,否则执行数字加法

    var a = "42"
    var b = "0";
    var c = 42;
    var d = 0;
    a + b ; // "420"
    c + d ; // 42
    
    var e = [1,2];//首先对其调用ToPrimitive抽象操作,再调用[[DefaultValue]],以数字作为上下文
    var f = [3,4];
    e + f ; //"1,23,4"
    
    布尔值到数字的隐式强制类型转换
    function onlyOne(){
        var sum = 0;
        for(var i=0;i<arguments.length;i++){
            if(arguments[i]){
                sum += arguments[i];
            }
        }
    }
    var a = true;
    var b = false;
    onlyOne(b,a);       //true
    onlyOne(b,a,b,b);   //true
    onlyOne(b,a,b,b,a)  //false
    
    隐式强制类型转换为布尔值
    • if(..)语句中的条件判断表达式
    • for(..;..;..)语句中的条件判断表达式
    • while(..)和do..whilee(..)循环中的条件判断表达式
    • ?:中的条件判断表达式
    • 逻辑运算符||和&&左边的操作数(作为条件判断表达式)

    以上情况中,非布尔值会被隐式强制类型转化为布尔值,遵循前面介绍过得ToBoolean抽象规则

    ||和&&

    准确来说,应该将它们称为"选择器运算符"
    它们的返回值是两个操作数中的一个(且仅一个)

    • ||和&&首先会对第一个操作数执行条件判断,如果其不是布尔值,则先进行ToBoolean强制类型转换,然后再进行条件判断
    • 对||来说,如果条件判断结果为true则返回第一个操作数的值(不一定是布尔值),如果是false直接返回第二个操作数的值
    • 对&&来说,如果条件判断为true就直接返回第二个操作数的值,为false直接返回第一个操作数的值
    • 在if和for中其实会隐式将||和&&的返回结果隐式转换为布尔值从而进行条件判断
    a || b
    //相当于
    a ? a : b
    
    a && b 
    //相当于
    a ? b : a
    
    符号的强制类型转换
    • ES6允许从符号到字符串的显示强制类型转换,然而隐式强制类型转换会产生错误
    • 符号不能够被强制类型转换为数字(不管显隐),但可以强制类型转换为布尔值

    宽松相等和严格相等

    正确的解释是:“==允许在相等比较上进行强制类型转换,而===不允许”

    抽象相等
    • 如果两个值的类型相同的情况下
      • (1)先注意几个常规的情况:
        • NaN不等于NaN
        • +0等于-0
      • (2)两个对象指向同一个值是则视为相等,不发生强制类型转换
      • 不符合以上情况,就根据同类型直接比较是否相等
    • 如果两个值的类型不同的情况下
      • 字符串和数字之间的相等比较
        • 如果Type(x)是数字,Type(y)是字符串,返回x == ToNumber(y)的结果
        • 反之,返回ToNumber(x) == y的结果,即以数字为基准类型
      • 其他类型和布尔类型之间的相等比较
        • 如果Type(x)是布尔类型,则返回ToNumber(x) == y的结果,若类型不一致
        • 如果Type(y)是布尔值,则返回x == ToNumber(y)的结果,即也是以数字为基准类型
        • 待布尔值转换为数字后,剩下的是数字和非布尔的类型的比较了,此时要进行二次判断,即考虑数字和字符串的比较,null和undefined和情况,以及对象与非对象之间的相等比较,接下讨论这两种情况
      • null和undefined之间的比较
        • 如果x为null,y为undefined,则结果为true
        • 如果x为undefined,y为true,则结果为true
        • 即在==中null和undefined相等,除此之外其他值都不存在这种情况,即null与null和undefined相等,除此之外其他都不相等,反之undefined也一样
      • 对象和非对象之间的相等比较
        • 如果Type(x)是字符串或数字,Type(y)是对象,则返回x == ToPrimitive(y)的结果
        • 如果Type(x)是对象,Type(y)是字符串或数字,则返回ToPromitive(x) == y的结果,即先处理对象为优先,之后再根据返回的简单值进行二次判断,综合以上规则。
      • 比较少见的情况
      false == {};      //false
      "" == 0;          //true
      "" == {};         //false
      0 == {};          //false
      "" == [null];     //true
      
      • 安全运用隐式强制类型转换
        • 如果两边的值中有true或false,千万不要使用==
        • 如果两边的值中有[]、""或者0,尽量不要使用==
    抽象关系比较
    • 比较双方首先调用ToPrimitive,如果结果出现非字符串,就根据ToNumber规则将双方强制类型转换为数字来进行比较
    • 如果双方都是字符串,则按字母顺序来进行比较

    以上内容来自《你不知道的JS中卷》的知识整理

    相关文章

      网友评论

        本文标题:Javascript知识整理——强制类型转换

        本文链接:https://www.haomeiwen.com/subject/mysmjxtx.html