• JavaScript 数据类型转换


          JavaScript是一门动态类型语言,变量是没有类型的,可以随时赋予任意值。但数据本身和运算是区别类型的。因此需要进行数据类型转化,有些转换是自动进行的,有些转换则需要强制转化。

    1. 强制转换 

          强制转化使用三个构造函数:Number、String和Boolean,手动将各种类型的值转化为数字、字符串或者布尔值。  

    1.1 Number函数:强制转化为数值 

          将任意类型的变量转化为数字 

          原始类型值的转换规则

    1)数值:转换后还是原来的值

    2)布尔值:true转化为1,false转化为0

    3)undefined:转化为NaN

    4)null:转化为0

    5)字符串:转换规则较多,如下所示:

    ------如果字符串中只包含数字,转化为相应的十进制数值。eg:"1"转化为1,"123"转化为123,而"011"转化为11(忽略前导0);

    ------如果字符串中包含有效的浮点格式,转化为浮点数。eg:"12.3"转化为12.3(也会忽略前导0);

    ------如果字符串为空字符"",返回0;

    ------如果字符串中包含有效的十六进制格式,如"0xf",返回对应的十进制数值(由于忽略前导0,不能识别八进制数值);

    ------除上述规则外,其它情况下返回NaN。

     eg: console.log(Number("123"));  "123abc"--->NaN、""--->0、"0xf"--->15、undefined--->NaN、null--->0、false--->0;

           console.log(Number(" v12.34 ")); //12.34(Number函数会自动过滤一个字符串前导和后缀中的空格) 

           console.log(Number([])); //空数组转换为0 

          对象的转换规则

    1)首先调用对象自身的valueOf方法,如果结果为原始类型的值(数值、字符串或布尔值),再对该值使用Number函数,不再进行下面的步骤;

    2)如果valueOf方法返回复合类型的值,则调用对象自身的toString方法,如果结果为原始类型的值,再对该值使用Number函数,不再进行下面的步骤;

    3)如果toString方法返回的是复合类型的值,则报错。

        eg:Number({a:1}); //NaN

        上面代码的执行过程如下:

    if(typeof {a:1}.valueOf() === "object") {
         Number({a:1}.toString());
    else {
         Number({a:1}.valueOf());
    }

          上面代码分析如下:首先调用对象的valueOf方法,返回对象本身{a:1},所以toString方法的返回值"[Object Object]"使用Number函数,结果为NaN。

          如果toString方法返回的是复合类型的值,则会报错。

    var obj = {
        toString: function() {
            console.log("toString");
            return {};   
        },
        valueOf: function() {
            console.log("toString");
            return {};
        }
    }
    Number(obj);

          上述代码中,valueOf方法和toString方法返回的都是对象,Number方法报错:"TypeError: Cannot convert object to primitive value"。

    Number({valueOf: function() {return 2; }});
    Number({toString: function(){ return 3; }});
    Number({valueOf: function(){ return 2;}, toString: function() {return 3;}});

          上述代码的执行结果分别是:2,3,3。第一个对象返回valueOf方法的值,第二个对象返回toString方法的值,第三个对象表示valueOf方法先与toString方法执行。

    1.2 String函数:强制转化为字符串

          可以将任意类型的值转化为字符串。

          原始类型值的转化规则

    1)数值:转化为相应的字符串

    2)字符串:转化为原来的值

    3)布尔值:true转化为"true",false转化为"false"

    4)null:转化为"null"

    5)undefined:转化为"undefined" 

          对象的转化规则

    1)首先调用对象自身的toString方法,如果返回的是原始类型的值,对该值使用String函数,不再进行下面的步骤;

    2)如果toString方法返回的是复合类型的值,再调用对象自身的valueOf方法,如果返回原始类型的值,对该值使用String函数, 不再进行下面的步骤;

    3)如果valueOf方法放回的是复合类型的值,报错。

          String函数的这种过程正好与Number函数正好相反。

          eg: String({a:1}); //"[Object Object]" 

          上述代码相当于String({a:1}.toString()); //"[Object Object]"

    var obj = {
        toString: function() {
            console.log("toString");
            return {};   
        },
        valueOf: function() {
            console.log("toString");
            return {};
        }
    }
    String(obj);

          上述代码中toString方法和valueOf方法返回的都不是原始类型的值,那么String方法报错:"TypeError: Cannot convert object to primitive value"。

    String({toString: function(){ return 3; }});
    String({valueOf: function() {return 2; }});
    String({toString: function() {return 3;}, valueOf: function(){ return 2;}});

          上述代码的执行结果分别为:3 2 3。第一个对象返回toString方法,第二对象返回valueOf方法,第三个对象说明toString方法咸鱼valueOf方法执行。

    1.3 Boolean函数:强制转化成布尔值

          可以将任意类型的值转化为布尔值。 

          原始类型值得转化规则

          仅有7个值转化为false,这7个值分别是:null、undefined、+0、-0、""、NaN、false,其它值则转化为true;

          对象的转化规则

    1)所有对象都转化为true,包括false对应的布尔对象;

    2)空数组和空对象也转化为true。 

          eg:Boolean(false); //false      Boolean(new Boolean(false)); //true      Boolean([]); //true;      Boolean({}); //true; 

          对于数组,三种方式的强制类型转换

    eg:Number([]); //0   Number([1,2,3]); //NaN   String([]); //""   String([1,2,3]); //"1,2,3"  Boolean([]); //true   Boolean([1,2,3]);// true

     

    2. 自动转换

          当遇到以下3种情况,JavaScript会进行自动类型准换。

    1)不同类型数据进行互相运算;

    2)对非布尔值类型的数据求布尔值;

    3)对非数值类型的数据进行一元运算(+,-); 

    2.1 自动转化为数值

          当JavaScript遇到预期为数值的地方,会自动将非数值的参数转化为数值,转化规则与强制转化为数值规则一致,即在预期为数值的地方,自动调用Number方法。

          除了"+"运算符有可能将值转化为字符串外,其它运算符将两侧的值自动转化为数值。

    eg: ('5' - '2'; //3)  ('5' * '2' //10)   (false - 1; //-1)   (true - 1; //0)   ('1' - 1; //0)  ( '5' * []; //0)   (false / '4'; //0)   ("abc" - 1; //NaN)

          上述例子是二元算术运算符的例子,JavaScript中的两个一元运算符,一元加运算'+'和一元减运算'-'也会将运算因子自动转化为数值。 

    eg:(+'abc'; //NaN)  (-'abc'; //NaN)   (+true; //1)   (-false; //0)

    2.2 自动转化为字符串

          当JavaScript遇到预期为字符串的地方,会自动将非字符串的数据转化为字符串,转化规则与强制转化为字符串的规则一致。

          自动转化为字符串的情况发生在,'+'运算中,当一个运算因子为字符串,而另一个运算因子为非字符串时,自动将非字符串的数据转化为字符串。

    eg:('5' + 123; //"5123")('5' + true; //"5true")('5' + {}; //"5[Object Object]")('5' + []; //"5")('5' + function() {}; //"5function() {}")('5' + undefined; //"5undefined")('5' + null; //"5null")

    2.3 自动转化为布尔值

          当JavaScript遇到预期为布尔值得地方,会自动将非布尔值的参数转化为布尔值,转化规则与强制转化为布尔值规则一致。 

          除了6个值,分别是undefined、null、+0、-0、""、NaN是自动转化为false外,其它值自动转化为true。

          if(!undefined && !null &&  !0 && !"" && !NaN) {console.log(true);} //true

          2.4 总结

          由于自动转换有很大的不确定性,因此在预期为数值、字符串、布尔值的地方,全部使用Number()、String()、Boolean()进行显示转换。

    3. 加法运算符的类型转换 

          加法运算符(+)需要特别讨论,因为它涉及到两种类型的运算(加法和字符连接),所以不单要考虑数据类型转换,还需确定运算的类型。

    3.1 三种情况 

          加法运算符的类型转化,可以分为如下三种情况讨论:

    1)运算因子之中存在字符串

          只要有一个运算因子为字符串,那么执行的是字符连接操作,另一个运算因子会自动转化为字符串。

    2)两个运算因子都为数值或布尔值

          这种情况下,执行加法运算,布尔值转化为数值。eg: true + 5; //6    true + true; //2

    3)运算因子之中存在对象

          运算因子之中存在对象(更准确地说:存在非原始类型的值),首先调用对象的valueOf方法,如果返回的是原始类型的值,则依据上面两条规则进行运算。如果返回的是复合类型的值,则调用toString方法,对返回值运用上面两条规则。

           1 + [1,2]; //"11,2"

           首先调用[1,2].valueOf(),返回数组[1,2]本身,则继续调用[1,2].toString(),返回"1,2",所以最终结果为"11,2"。

           1 + {a:1}; //"1[Object Object]"

           首先调用对象{a:1}的valueOf方法,返回的是对象本身,接着调用对象{a:1}的toString方法,返回字符串"[Object Object]",所以最终结果是"1[Object Object]"

           有趣的是,如果更换上例中前后因子的顺序,结果不一样了。

           {a:1} + 1; //1

           原来此处,js引擎将{a:1}解析为代码块,并不解析为对象。{a:1}代码块没有返回值,因此原式相当于{a:1};+1,结果就是1。为了避免这种情况,要将{a:1}放置在括号()中,这样js引擎不会将他解析为代码块,而是解析为对象处理。({a:1}) + 1; //"[Object Object]1"

           1 + {valueOf: function() {return 2;}};//3 此代码中,valueOf方法返回数值2,因此最终结果为3。

           1 + {valueOf: function() { return {};}};//"1[Object Object]" 此代码中,valueOf方法返回一个空对象,继续调用toString方法,返回"[Object Object]",所以最终结果为"1[Object Object]"。

           1 + {valueOf: function() { return {};}, toString: function() { return 2; }};//3 此代码中,valueOf方法返回空对象,非原始类型值,继续调用toString方法,返回数值2,所以最终结果是3。

           1 + {valueOf: function() { return {};}, toString: function() { return {};}};//报错:"TypeError:can not covert object to primitive value" 此代码中,valueOf返回空对象,继续调用toString方法,返回空对象,非原始类型值,因此报错。

    3.2 四个特殊表达式

    1)空数组 + 空数组   eg: [] + []; //""  此代码中,首先对空数组调用valueOf方法,返回数组本身,因此再对空数组调用toString方法,返回空字符串,因此最终结果是空字符串""。

    2)空数组 + 空对象   eg: [] + {}; //"[Object Object]" 此代码中,等同于空字符串""与"[Object Object]"相加,因此最终结果为"[Object Object]"

    3)空对象 + 空数组   eg: {} + []; //0  此代码中,{}被解析为空代码块,因此原表达式等同于+ [],此时(+)表示一元加运算,对空数组求正值,将[]强制转化成数值,首先调用valueOf方法,返回数组本身,因此继续调用toString方法,返回"",再执行Number(""),最终结果为0。+[] 代码执行过程为:Number([]); Number([].toString()); Number(""); 如果不将{}解析为代码块,则有:({a:1}) + []; //"[Object Object]"。

    4)空对象 + 空对象   eg: {} + {}; // 此代码中,第一个{}被解析为代码块,因此原表达式等同于+ {},执行一元加运算,将{}强制转化为数值,首先调用valueOf方法,返回对象本身,因此继续调用toString方法,返回"[Object Object]",再执行Number("[Object Object]"),最终结果为NaN。+ {}代码执行过程为:Number({}); Number({}.toString()); Number("[Object Object]");

          {} + {}; 此代码中,如果第一个{}不被解析为代码块,最终结果为:"[Object Object][Object Object]"。情况如有:({}) + {};       ({} + {});      console.log({} + {});      var a = {} + {}; a;

          需要指出的是对于情况3)和4),Node.js的运行结果不同于浏览器环境。

          {} + []; // "[Object Object]"

          {} + {}; //"[Object Object][Object Object]"   

          可以看到Node.js并未将第一个{}解析为代码块,原因是Node.js的命令行环境,内部执行机制大致如下所示:

          eval.call(this,"(function() { return {} + {}; } }).call(this);");

          Node.js把命令行输入都放在eval中执行,因此不会把起首的大括号理解为空代码块加以忽略。


    引用:http://javascript.ruanyifeng.com/grammar/conversion.html#toc5 

    时间:2014-10-15

    地点:合肥科大图书馆 

  • 相关阅读:
    跟我一起写 Makefile
    NFS服务器配置
    q
    tar命令的详细解释
    etc/xinetd.d目录介绍
    ubuntu 10.04下的配置tftp服务器
    莫队板子
    Day8(分块)
    字符串板子
    字符串练习题
  • 原文地址:https://www.cnblogs.com/sun-mile-rain/p/4026912.html
Copyright © 2020-2023  润新知