zoukankan      html  css  js  c++  java
  • JavaScript中的类型转换(二)

    说明: 本篇主要讨论JavaScript中各运算符对运算数进行的类型转换的影响,本文中所提到的对象类型仅指JavaScript预定义的类型和程序员自己实现的对象,不包括宿主环境定义的特殊对象(比如浏览器定义的对象)

    上一篇中讨论了JavaScript中原始类型到原始类型的转换,原始类型到对象类型的转换和对象类型到原始类型的转换,这里先提出一个问题

    var a = undefined;
    if(a){
        console.log('hello');
    }else{
        console.log('world');
    }
    console.log(a == false);

    以前我不对JavaScript的一知半解的时候,我以为上面的代码回先后输出'world'和'true',但是经过执行代码,发现结果是'world'和'false'.undefined确确实实可以被转换为false,但是在使用==操作符对undefined和false两个值进行相等性比较时,由于两个操作数的类型不同,这里会发生类型转换,并且undefined并没有被转换为boolean类型然后跟false比较,所以本篇讨论下运算符对运算数类型转换的影响.

    1.+(二元),==,!=,>,<,<=,>=

    二元+运算符用于把两个数字相加或者连接两个字符串,所以该运算符期望的运算数类型为数字或者字符串。当运算数都是数字或者字符串时,结果是显而易见的,否则的话就会现对操作数进行类型转换,把操作数转换为数字或者字符串,然后进行数学相加或者连接字符串的运算。操作数会照下面的规则进行类型转换:

    1.如果其中任一操作数是对象类型,先执行对象到原始类型的转换:对于Date对象,通过调用toString方法得到原始类型的值;对于其他对象,优先尝试valueOf方法,然后再尝试toString方法,如果valueOf和toString都无法得到原始类型的值,则会抛出异常

    2.现在两个操作数都是原始类型了,如果其中一个操作数是字符串,则把另外一个原始类型的操作数转换成字符串,然后执行字符串连接运算

    3.否则,把两个操作数都转换成数字进行数学加法运算

    console.log('10'+null);//10null
            console.log('10'+undefined);//10undefined
            console.log('10'+false);//10false
            console.log('10'+true);//10true
            console.log('10'+10);//1010
            var o1 = {};
            console.log('10'+o1);//10[object Object] 对象默认的valueOf方法返回的不是原始类型,所以会调用toString方法
            o1.toString = function(){
                return 'o1';
            }
            console.log('10'+o1);//10o1
            o1.valueOf = function(){
                return null;
            }
            console.log('10'+o1);//10null 对象现在有了一个返回原始类型的valueOf方法,不再调用toStringconsole.log(10+null);
            console.log(10+undefined);//NaN, undefinde转换成数字是Nan
            console.log(10+false);//10
            console.log(10+true);//11
            var o1 = {};
            console.log(10+o1);//10[object Object] 对象默认的valueOf方法返回的不是原始类型,所以会调用toString方法,而toString返回的是字符串,所以执行字符串连接
            o1.toString = function(){
                return true;
            }
            console.log(10+o1);//11
            o1.valueOf = function(){
                return null;
            }
            console.log(10+o1);//10 对象现在有了一个返回原始类型的valueOf方法,不再调用toString                var date = new Date;
            console.log(date + true);//Tue Aug 19 2014 10:32:49 GMT+0800 (中国标准时间)true
     

    使用==运算符比较两个运算数的相等性时,如果两个运算数类型不一致,就会发生类型转换,转换时遵循以下规则

    1.null和undefined是相等的

    2.如果一个操作数是数字,另一个操作数是字符串,则把字符串转换成数字再进行比较

    3.如果有布尔类型的操作数,把它转换成数字

    4.如果其中一个操作数是对象类型,把对象类型转换成原始类型再进行比较.当把对象转换成原始值时,优先使用valueOf方法,其次使用toString方法,但是与+运算符一样,Date对象是个特例,Date对象调用toString方法

    5.其余情况一律认为不想等

    到这里可以解释本文开始提出的问题了,undefined与false进行==比较,false先被转换成数字0,然后与undefined比较,属于情况5,返回false

    console.log(0 == null);//false
            console.log( 0 == undefined);// false
            console.log(0 == false);//true,false转换成0
            console.log(1 == true);//true,true转换成1
            console.log(true == '1');//true,true先转换成1,然后1转换成字符串'1'
            console.log(null == 'null');//false,情况5
            var o = {};
            console.log(o == '[object Object]');//true,toString方法返回'[object Object]'
            o.valueOf = function(){
                return '1';
            };
            console.log(true == o);//true,true先转换为1,o先调用valueOf得到一个原始值'1',数字与字符串比较,数字转换成字符串

    对于!=运算符,结果总是与==运算符的结果相反

    对于>,<(很萌有木有),<=,>=这四个比较运算符,期望的运算数类型与二元+一样,要么比较两个数字,要么比较两个字符串,如果运算数不全位数字或字符串,则会发生类型转换,转换的规则如下:

    1.如果任一操作数是对象类型,则先后尝试valueOf方法和toString方法把对象转换成原始类型,需要注意的是这里Date不再做特殊处理了,与其他对象一样

    2.经过第一步之后,两个操作数都是原始类型了,如果都是字符串,则进行字符串比较,如果都是数字,则进行数字比较

    3.否则,把两个原始类型都转换成数字,然后进行比较

    console.log(1 > null);//true,null->0
            console.log( 1 >= undefined);// false,undefined->NaN
            console.log(1 <= undefined);//false
            console.log(null > undefined) // false,null->0,undefinde->NaN
            console.log(null <= undefined)//false
            console.log('1' < true);//false,'1'->1,true->1
            console.log('1' > true);//false
            var o = {};
            o.toString = function(){
                return 10;
            };
            console.log(o > 9);//true, o->10
            console.log(o > '9')//true,o->10,'9'->9
            o.toString = function(){
                return '10';
            }
            console.log(o > 9);//true, o->'10','10'->10
            console.log(o > '9')//false,o->'10'
            o={};
            var o1={};
            console.log(o > o1);//o和o1都通过toString方法转换成了字符串,并且字符串内容是一致的
            console.log(o < o1);
            console.log(o >= o1);

    2.+(一元),-(一元和二元),*,++,--

    这几个运算符期望的运算数都是数字类型,所以当操作数类型不对时,会把操作数转换为数字

    var a = '10';
            console.log(+a);//+10
            console.log(1 - a);//-9
            console.log(a++);//10,但是此时a的类型已经发生了变化,++和--都需要一个左值,所以++'10'是错误的
            console.log(typeof a);//输出number,a的类型已经改变
            a = '10';
            var o = {};
            o.toString = function() {
                return '10';
            }
            console.log(o++);//10,o->'10'->10
            console.log(typeof o);//number
            o = {};
            o.toString = function() {
                return '10';
            }
            o.valueOf = function(){
                return false;
            }
            console.log(++o);//1,优先使用valueOf方法
            console.log(typeof o);//number

    3.总结

    从本文的分析可以看出,JavaScript中的大部分运算符都只能对原始类型的操作数进行运算,其中一部分只能对数字类型进行运算,另一部分可以对数字和字符串类型进行运算,当进行运算时,运算数与预期的类型不相符合时,会通过先后调用valueOf和toString方法将对象类型转换为原始类型(需要注意Date对象的特殊性),然后再将原始类型转换为数字或者字符串.

  • 相关阅读:
    一张图片入门Python
    4.1. 如何在Windows环境下开发Python
    你必须知道的EF知识和经验
    XUnit的使用
    如何使用NUnit
    Entity Framework 不支持DefaultValue
    Have You Ever Wondered About the Difference Between NOT NULL and DEFAULT?
    Validation failed for one or more entities. See 'EntityValidationErrors' property for more details
    Entity Framework 与多线程
    sqlite中的自增主键
  • 原文地址:https://www.cnblogs.com/onepiece_wang/p/3921787.html
Copyright © 2011-2022 走看看