
深入浅出JavaScript中的隐式转换
S是一门弱类型语言,在声明变量的时候不需要声明变量的类型,并且不同类型的数据可以进行计算,这都得益于JS中在语言设计时的创建的隐式转换。
我们知道JS有7大数据类型
分为基本类型(原始值):String Number Boolean null undefined Symbol
复杂引用类型(引用值):Object
隐式转换作为JS中的一个难点,因为js在一些特定操作符的情况下会调用隐式转换,这也是js灵活的地方,两个操作符"+"和"=="是比较常见的出现隐式转换的操作符
一、既然是要隐式转换,那麽必然有一套约定俗成的规则,而不是随便转化。
隐式转换主要分为三种方式
- 将值转化为原始值 => toPrimitive
- 将值转化为String => ToString
- 将值转化为Number => ToNumber
2.1 通过toPrimitive将值转化为原始值
js引擎内部有一个抽象操作ToPrimitive,他有着这样的签名, ToPrimitive(input, PreferredType?) input是传入的值,PreferredType是可选参数,表示转化为什么类型,转化后的结果并不一定是这个参数所指定的结果,但是一定是一个原始类型的值
如果PreferredType被标记为Number,则会进行如下操作进行转化
如果输入的值已经是一个原始值,则直接返回该值
否则如果是一个对象,则调用对象的valueOf()方法,如果valueOf()返回的是一个原始值,则直接返回得到的值
否则调用这个对象的toString()方法,如果toString()返回的是一个原始值,则直接返回该值
否则抛出TypeError异常
如果PreferredType被标记为String,则会进行如下操作转化
如果输入的值是一个原始值,则直接返回该值
否则如果是一个对象,则调用对象的toString()方法,如果toString()方法返回的是一个原始值,则直接返回该值
否则调用这个对象的valueOf()方法,如果valueOf()返回的是一个原始值,则直接返回该值
否则抛出TypeError异常
既然PreferredType是一个可选值,那么不传默认会被标记为什么呢
如果传入值为Date类型,则标记为String
如果传入的值为其他引用类型,则标记为Number
上面主要提到了valueOf和toString方法,那么我们能否保证任何情况下都有这两个方法呢,答案是肯定的
只要是引用类型的我们可以直接顺着原型链找到Object.prototype,我们会发现在原型上就有toString和valueOf方法,故而是一定可以找到的
先看看对象的valueOf函数,其转化的结果是什么
对于js的常见内置对象:Date, Array, Math, Number, Boolean, String, Array, RegExp, Function。
Number、Boolean、String这三种构造函数生成的基础值的对象形式,通过valueOf转换后会变成相应的原始值。如:
Date是一个特殊的对象,通过valueOf会转化为毫秒值
其他的都返回this,也是引用本身
再看看toString函数,其转换的结果是什么?对于js的常见内置对象:Date, Array, Math, Number, Boolean, String, Array, RegExp, Function。
Number、Boolean、String、Array、Date、RegExp、Function这几种构造函数生成的对象,通过toString转换后会变成相应的字符串的形式,因为这些构造函数上封装了自己的toString方法。如:
var obj = {}
obj.toString() // '[Object object]'
Math.toString() // '[Object Math]'
一些思考
从上面valueOf和toString两个函数对对象的转换可以看出为什么对于ToPrimitive(input, PreferredType?),PreferredType没有设定的时候,除了Date类型,PreferredType被设置为String,其它的会设置成Number。
- 因为对于我们不知道要转换什么类型的时候,最好是返回其本身,标记为Number先调用valueOf的时候除了在String、Number、Boolean生成的对象字面量转化为对应的原始类型值,还有Date返回了对应的毫秒值以外,其他都返回了本身this
- 为什么默认使用标记为Number呢,因为Number会先调用valueOf(),而不是像标记为String无脑调用toString方法转化为字符串
- 为什么Date在没有标记的时候默认标记为String先调用toString()方法,因为我们不知道要转化为什么,所以没必要转化为一个特别大的数字,所有调用toString转化为String
通过ToNumber将值转换为数字
2.3 通过ToString将值转化为字符串
二、从理论到实践去看JS的隐式转换
1. 从第一章理论知识和规则我们已经了解了js是如何对不同数据类型进行隐式转换的,下面我们来几道题目实战一下
== 运算符的隐式转换
总结一下:
上面主要分为两类
类型相同类型相同时,没有类型转换,注意NaN不与任何值相等即可
类型不同
x,y 为null、undefined两者中的一个 返回true
x,y为Number和String类型时,转换为Number进行比较
有Boolean时,转化为Number比较
一个Object类型,一个String或者Number类型,将Object按类型转换为原始值后,再按上面三步比较
看一些例子:
在我们来看看最开始的那道题目,我们是不是有些思路了
总结
