当前位置: 首页 > Web前端 > JavaScript

理解JavaScript中的类型转换

时间:2023-03-27 17:38:39 JavaScript

1。什么是类型转换?类型转换的定义很容易理解,就是将值从一种类型转换为另一种类型,例如从String类型转换为Number类型,'42'→42。但是,如果我们对JS中的类型转换规则不够了解,就会遇到很多扑朔迷离的问题,就好像不学理化一样,人生充满魔力。JS中的类型转换大致可以分为两种:显式类型转换和隐式类型转换。两者的区别非常明显,比如显式类型转换'String(42)',我们可以清楚地看到这行代码是将42转换为String类型。虽然隐式类型转换通常是某些操作的副作用,比如''+42,但并不那么明显,它是加法操作的副作用。如果你不懂JS中的类型转换,下面的例子可能会让你王得发。//ex.1console.log([]==![]);//true//ex.2consta1={},a2={};console.log(a1a2);//falseconsole.log(a1>=a2);//真console.log(a1<=a2);//true//ex.3consta3={i:1,valueOf(){returnthis.i++;},};控制台日志(a3==1&&a3==2);//true这些奇怪的现象背后是有原因的,当然,前提是你了解它。2.类型转换的抽象操作在详细介绍显式和隐式类型转换之前,我们需要了解String、Number、Boolean类型转换的基本规则。这些类型之间转换的抽象操作(或转换规则)在ES5规范中定义。下面简单介绍几种抽象的运算规则。ToPrimitive(负责将对象转换为基本数据类型)为了将一个值转换为对应的基本类型值,抽象操作ToPrimitive会首先检查该值是否有valueOf方法。如果存在并且该方法返回原始值,则使用该值进行转换。如果不是,则使用toString的返回值(如果存在)进行转换。如果valueOf和toString都不返回原始值,则会引发TypeError。例如://ex.4consttestObj={};console.log(testObj.valueOf());//{}testObj本身console.log(testObj.toString());//'[objectObject]'stringcharacterString/*首先调用testObj的valueOf方法,返回值是testObj本身,不是原始(基本)值类型;所以调用testObj的toString方法返回的是字符串'[objectObject]',是一个基本类型,所以要用'[objectObject]'来操作。*/console.log(''+testObj);//'[objectObject]'testObj.valueOf=()=>'valueOf';/*此时调用testObj的valueOf方法,返回字符串'valueOf',是基本类型,所以返回值会用于操作,不再调用toString方法。*/console.log(''+testObj);//'valueOf'ToString(负责将非字符串转换为字符串)a.当待转换的值是基本类型时,待转换的值转换为String后的结果null'null'undefined'undefined'true,false'true','false'Symbol('example')只支持显式类型转换得到'Symbol('example')'普通数0,1,2符合一般规则'0','1','2'极大或极小数1/10000000使用指数形式'1e-7','1e+21'b。当要转换的值是对象时,如果是显式类型进行转换,调用该值的toString方法。如果是隐式类型转换,先通过ToPrimitive操作转换为基本类型,再按照规则a转换为String类型。当待转换值的valueOf方法和toString方法未修改时,常用的对象转换如下:待转换值转换成String后,结果为Object'[objectObject]'Array[1,2,3]用逗号分隔'1,2,3'的每个数组元素为null或undefined,[null],[undefined]空字符串''美国英语日期格式的日期字符串,'FriOct15202114:04:28GMT+0800(ChinaStandardTime)'Function表示函数源代码的一个字符串ToNumber(负责将非数字转换为数字)。将待转换的值转换为Number后的结果为true1false0undefinedNaNnull0string'42','42px'基本遵循number常量的相关规则,处理失败返回NaN42,NaNsymbol无法转换为Object等复杂类型先转换为basic通过ToPrimitive类型,然后转换为Number类型。例如:console.log(Number([null]));//0//[null]从ToPrimitive转换为基本类型是一个空字符串'',从空字符串转换为Number得到0ToBoolean值在JavaScript中可以分为以下两类:(1)可以类型转换为false的值:undefined,null,+0,-0andNaN,false,''(2)Others(按类型转换为true的值),即除上述以外值。需要注意的是,有一个概念叫做假值对象。false值对象和普通对象的区别在于,当它转换为布尔值时,它会得到false。这种情况很少见,但是确实存在,比如document.allobject,console.log(!!document.all);//错误的。好了,既然我们对这些抽象操作有了一定的了解,下面就可以稍微深入一点类型转换了。3.显式类型转换字符串和数字的显式类型转换字符串和数字之间的类型转换应该是我们最常见的一种,它们之间的显式类型转换是通过JS原生构造函数String和Number实现的,但是构造函数是没有通过新机器调用。这两个函数在进行类型转换时遵循了ToString和ToNumber的抽象操作。例如:console.log(Number('3'));//3console.log(字符串(3));//'3'显式解析字符串解析字符串中的数字(parseInt,parseFloat)转换字符虽然字符串转换为数字的结果是数字,但是两者的转换规则不同。a.与Number相比,parseInt允许传入的字符串参数包含非数字字符,并且从左到右依次解析,遇到非数字字符就停止解析。例如console.log(parseInt('10px'));//10,console.log(Number('10px'));//NaN.b.parseInt是一个字符串函数。当传入的第一个参数不是字符串时,会先转为字符串再解析。C。parseInt还有第二个参数,表示用于解析的base,如console.log(parseInt('11',8));//9,以八进制解析'11'。该参数的范围是2-36。如果传入范围外的值(如果传入0,则设置为十进制),则返回NaN。使用parseInt(str,radix)时,radix没有指定默认值(只是在大多数情况下,radix会默认设置为10),这意味着如果你不传入这个参数,结果可能就是你想要的预计在外面。例如当str以0x或0X(大写X)开头时,radix会默认设置为16,所以当console.log(parseInt('0x11'));//17会得到17。有一个很有趣的例子:console.log([1,2,3].map(parseInt));//[1,NaN,NaN],用到这个参数,result数组的三项分别是parseInt(1,0),parseInt(2,1),parseInt(3,2),在第一项中,因为基数是0,所以被当做十进制,所以返回1;第二项中,由于基数为1,不在合法范围(2-36)内,所以返回NaN;第三项,因为基数是2,所以要解析的参数是3(二进制只有0和1的表达式是合法的),所以返回NaN。显示转换Boolean与String和Number相同,Boolean是显式的ToBoolean类型转换,遵循ToBoolean运算规则。不过一般!!方法用的比较多。例如:console.log(Boolean(1),!!1);4.隐式类型转换隐式类型转换一般是其他操作的副作用。加法操作:如果操作数是对象,则先通过ToPrimitive操作将对象转为原始类型,然后继续操作。如果其中一个操作数是字符串(String)类型,则另一个操作数也转换为字符串(String)类型进行字符串拼接。如果操作数中没有字符串(String)类型,则将两个操作数视为数字(Number)类型,进行加法运算。例如://因为'hello'是一个字符串,将1转换为'1',然后进行字符串拼接console.log(1+'hello');//'1hello'//因为没有字符串类型的操作数,所以进行加法运算,将true转换为数字类型1,所以结果为2console.log(1+true);//2//因为[2]是一个对象类型,通过ToPrimitive操作后,将其转化为字符串'2',然后需要将1转化为'1'进行字符串拼接console.log(1+[2]);//'12'减法、除法、乘法等操作:如果操作数是object,先通过ToPrimitive操作将object转化为原始类型,然后继续操作。用两个操作数作为数字进行操作。例如://[3]-[2]→'3'-'2'→3-2=1console.log([3]-[2]);//1//3-1=2console.log([3]-true);//2将其他类型隐式转换为Boolean的操作:以值作为判断条件时。比如if语句中的条件判断表达式;for循环语句中的条件判断表达式;while循环和do..while循环中的条件判断表达式;三元运算符(?:)中??的条件判断表达式;逻辑运算符||中的值&&用作条件判断表达式。该值会隐式转换为布尔类型进行判断,遵循ToBoolean运算规则。松散相等(==):在JS中比较关系时,松散相等(==)经常被解释为:“只比较两者的值是否相等,不比较类型”。事实上,这种解释存在一些问题。我们应该如何理解这个解释中的“价值”呢?例如,我正在比较console.log(0=='');//true,0和空串'',两者的原始值和类型不同,但大致相等。更准确的解释应该是“在进行松散相等关系比较时,如果两种类型相同,只比较两者的值是否相同;如果两种类型不同,则需要进行类型转换为同一类型,然后比较值是否相同”。也就是说,当比较两个不同类型的值是否松散相等时,就会发生隐式类型转换。松等式中,类型不同时的类型转换规则如下(假设两个操作数分别为x和y):如果x和y的类型分别为字符串(String)和数字(Number),则字符串类型转换为数字,然后进行比较。//先将字符串'1'转为数字1,然后进行比较console.log(1=='1');//trueBoolean类型的操作数需要转为Number(数字)类型。//先将false转为0,然后根据规则1,将'0'转为0,然后比较console.log('0'==false);//true如果一方是对象类型,则为需要先通过ToPrimitive抽象操作规则,转换成基本类型再继续比较。//先将object类型的数组[1]转为字符串'1',然后根据规则1,将字符串'1'转为数字1,然后比较console.log([1]==0);//falsenull和undefined大致相等。可以说,在松散相等的比较中,null和undefined是一回事。另一件需要知道的事情:?NaN不等于NaN。?+0等于-0大于(>),小于(<),大于等于(>=),小于等于(<=):当执行大于和小于两个比较时比:一个。如果有对象类型,首先通过ToPrimitive操作转换为基本类型进行比较。b.如果都是字符串,则通过ASCII码值进行比较。C。如果其中一个不是字符串,则通过ToNumber抽象操作将两者都转换为Number类型,然后进行比较。当进行大于等于和小于等于的两次比较时:大于等于表示不小于,即a>=b的结果为!(a'[objectObject]'都是falseconsole.log(a1a2);//false//进行松散相等比较时,两者类型相同,不会进行类型转换,但是比较两者的值,a1和a2显然指向不同的地址,所以a1==a2=也是falseconsole.log(a1==a2);//false//小于等于大于等于大于小于结果取反,所以为trueconsole.log(a1>=a2);//真console.log(a1<=a2);//trueex.3://ex.3consta3={i:1,valueOf(){returnthis.i++;},};console.log(a3==1&&a3==2);//true//a3是一个对象类型,通过ToPrimitive操作,转换为基本类型得到a3.i(即1),所以a3==1为true//但是上面执行valueOf时,i是自增一次,所以比较a3==2时,当a3转换为基本类型值时,结果为2,所以a3==2也为真。