JavaScript中的隐式类型转换
栏目: JavaScript · 发布时间: 5年前
内容简介:这里就要提到原生类型内建的包装对象,包括:在操作原始数据类型的属性和方法时,JS会自动将原始类型转换成一个对应的包装对象。此时该对象就拥有了属于它本身的一系列属性和方法。所以当我们定义了一些基本数据类型,想访问其对应的属性或方法时,就需要将其转换为这个值的包装对象,然而现实中并不需要这么麻烦,这是因为JS运行的宿主对象(浏览器等)将会自动地包装基本类型值来满足这样的访问。所以我认为所谓JS万物皆对象,或许只是自动的实现了一些隐式的转换。关于 === 和 == 比较操作符的不同,在比较浅显的认知中,全等操作符
这里就要提到原生类型内建的包装对象,包括:
- String()
- Number()
- Boolean()
- Array()
- Object()
- Function()
- RegExp()
- Date()
- Error()
- Symbol()
在操作原始数据类型的属性和方法时,JS会自动将原始类型转换成一个对应的包装对象。此时该对象就拥有了属于它本身的一系列属性和方法。所以当我们定义了一些基本数据类型,想访问其对应的属性或方法时,就需要将其转换为这个值的包装对象,然而现实中并不需要这么麻烦,这是因为JS运行的宿主对象(浏览器等)将会自动地包装基本类型值来满足这样的访问。所以我认为所谓JS万物皆对象,或许只是自动的实现了一些隐式的转换。
严格相等(===)和宽松相等(==)
关于 === 和 == 比较操作符的不同,在比较浅显的认知中,全等操作符(===)会比较类型,而比较运算符(==)则不会比较类型。 然而我们看一下其在MDN中的定义:
全等操作符(===)比较两个值是否相等,两个被比较的值在比较前都不进行隐式类型转换。 相等操作符(==)比较两个值是否相等,在比较前将两个被比较的值转换为相同类型。
由此得出这两个操作符最大的不同,就是在比较前是否会进行 隐式类型转换 。
我们也经常会见过很多隐式转换比较的题目,如:
undefined == null //true [] == [] //false [] == ![] //true {} == !{} //false ![] == {} //false [] == !{} //true [1,2] == ![1] //false 复制代码
所以上述的是依据什么规则如何进行转换?在ECMA文档中的 抽象相等比较算法 具体描述了如下规则。
抽象相等比较算法
在比较x == y,其中 x 和 y 是值,结果返回 true 或 false 。比较规则如下:
1.当 x 的类型与 y 的类型相同时:
a. 如果x的类型为Undefined,返回true。 b. 如果x的类型为Null,返回true。 c. 如果x的类型为Number,则如下: i. 如果 x 为 NaN, 返回 false.(NaN == NaN 为false) ii. 如果 y 为 NaN, 返回 false. iii. 如果 x 和 y 的值相同, 返回 true. iv. 如果x为+0,y为−0,返回 true. v. 如果x为−0,y为+0,返回 true. 其他返回 false. d. 如果x是string类型,那么假如x和y是完全相同的字符序列(相同的长度和相应位置的相同字符),则返回true。否则,返回false。 e. 如果x是布尔类型,假如x和y都为true或都为false,则返回true。否则,返回false。 f. 如果x和y引用同一对象,则返回true。否则,返回false。 复制代码
2. x 和 y 类型不相同的情况:
2. 如果x为null,y为undefined,则返回true。 3. 如果x为undefined,y为null,则返回true。(其余的任何类型与undefined和null相比都为false) 4. 如果x是数字类型,y是字符串类型,则返回x == ToNumber(y)的比较结果. 5. 如果x是字符串类型,y是数字类型,则返回ToNumber(x) == y的比较结果. 6. 如果x是布尔类型,则返回ToNumber(x)==y的比较结果. 7. 如果y是布尔类型,则返回x == ToNumber(y)的比较结果. 8. 如果x是字符串或数字类型,y 是对象类型,返回比较结果x== ToPrimitive(y)。 9. 如果x是对象类型,y是字符串或数字类型,返回比较结果ToPrimitive(x)==y。 10. 其他则返回false 复制代码
上述规则看起来很复杂,但总结起来其实只有以下几点:
- 两个引用类型比较,只需判断它们是不是引用了同一个对象,是返回true,否则为false。
- undefined 和 null 两者互相比较或者与自身比较,结果是true。它俩与其他任何值比较的都为false。
- NaN与任何值比较包括它自身结果都是false。
- 引用类型和基本数据类型进行比较,两者最后都会转换成基本数据类型再进行比较。
- String,Boolean,Number中的任意两个进行比较,最后都会转为Number类型再进行比较。
现在我们再来看一下具体的类型转换过程
1. ToNumber
抽象操作ToNumber将非数字值转换为数字类型。
- 其中布尔类型 true 转换为1,false 转换为0。
- 字符串类型,""(空字符串)转为0,'123' 转为 123,'123px' 则被转为NaN(按照上述总结,NaN与任何类型比较都为false,此时就不需要再考虑其他情况),
- 特殊的,undefined 会转换为 NaN,null 会转换为 0,(按上述总结第3条,null 和 undefined 跟其他任何非该两个类型中其一的比较都为false。结果容易得出,就不需要再考虑其他类型转换了)。
- 至于引用类型,它们都需要先进行 ToPrimitive 转换为基本数据类型后再转换为数字类型。
2. ToPrimitive
抽象操作ToPrimitive将引用类型转为基本数据类型。
JS引擎内部转换为原始值ToPrimitive(obj,preferredType)函数接受两个参数,第一个obj为被转换的对象,第二个preferredType为希望转换成的类型(默认为空,接受的值为Number或String)
在执行ToPrimitive(obj,preferredType)时如果第二个参数为空并且obj为Date的实例时,此时preferredType会被设置为String,其他情况下preferredType都会被设置为Number如果preferredType为Number。
转换为Number数字类型的过程为首先调用obj.valueOf(),如果执行结果是基本数值类型就返回该值,否则就调用obj.toString(),返回该字符串类型值。
转换为String数字类型的过程为首先调用obj.toString(),如果执行结果是基本数值类型就返回该值,否则就调用obj.valueOf(),返回该字符串类型值。
上述规则总结起来基本就是:
- ToPrimitive转换为原始数据类型时,如果是基本数据类型就直接返回该类型值。
- 如果不是,则优先调用valueOf方法(如果有),看其返回结果是否是基本类型,如果是,则返回。否则,再调用toString方法,转换为字符串类型后返回。
- 当类型为Date日期类型时,JS希望其优先被转换成字符串类型,则先调用toString方法,转换为字符串。
- 其他情况报错。因为从ES5开始,使用Object.create(null)创建的对象由于没有原型链,自然就也没有valueOf()和toString()方法,这种情况出现的很少,基本可以忽略。
在上图测试结果总结如下:
- 有所的object类型转换都会转换为"[object Object]"字符串
- 空数组[]会被转换为空字符串'', [1, 2, 3]会被转换为字符串'1,2,3',复杂类型的数组[{a: 1, b: 2}]会被转换为"[object Object],[object Object]"
- 日期对象会转换为字符串格式,如 new Date() 会转换为'Wed Apr 17 2019 19:52:56 GMT+0800 (中国标准时间)'
由此可以看出,对象、数组、日期类型最后基本都被转换为字符串类型。所以我们姑且可以将 ToPrimitive 看做将引用类型最后都转换为字符串类型。
3.ToBoolean
抽象操作ToBoolean将转为布尔类型。
对于布尔类型转换来说,假值(undefined、null、false、+0、-0、NaN、"")会被转换为false,除假值外的所有值都会被转换成true。
4.ToString
抽象操作ToString将转为字符串类型。
对于字符串类型也比较好理解,大部分的基本数据类型转换为字符类型时,基本就是在它基础上加了引号这么直观,比较特殊的就是+0、0、-0它们几个都会被转成相同的'0',还有那些极小和极大的数字将会转换为指数形式的字符串来表现,而引用类型转换成字符串的时候也跟它们ToPrimitive时候的规则一致(见上文ToPrimitive)。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
与孩子一起学编程
[美] 桑德Warren Sande、Carter Sande / 苏金国、姚曜 等 / 人民邮电出版社 / 2010-11 / 65.00元
一本老少咸宜的编程入门奇书!一册在手,你完全可以带着自己的孩子,跟随Sande父子组合在轻松的氛围中熟悉那些编程概念,如内存、循环、输入和输出、数据结构和图形用户界面等。这些知识一点儿也不高深,听起来备感亲切,书中言语幽默风趣而不失真义,让学习过程充满乐趣。细心的作者还配上了孩子们都喜欢的可爱漫画和经过运行测试的程序示例,教你用最易编写和最易理解的Python语言,写出你梦想中的游戏程序。 ......一起来看看 《与孩子一起学编程》 这本书的介绍吧!