类型转换的工具方法
valueOf
:返回这个对象逻辑上对应的原始类型的值。比如说,String
包装对象的valueOf()
,应该返回这个对象所包装的字符串。toString
:返回这个对象的字符串表示。用一个字符串来描述这个对象的内容。
**所有的对象都会继承到这两个方法。 以下是部分内置对象调用valueOf()
的行为: **
对象 | 返回值 |
---|---|
Array | 数组本身(对象类型)。 |
Boolean | 布尔值(原始类型)。 |
Date | 从 UTC 1970 年 1 月 1 日午夜开始计算,到所封装的日期所经过的毫秒数(原始类型)。 |
Function | 函数本身(对象类型)。 |
Number | 数字值(原始类型)。 |
Object | 对象本身(对象类型)。如果自定义对象没有重写valueOf方法,就会使用它。 |
String | 字符串值(原始类型)。 |
由上表可见,valueOf()
虽然期望返回原始类型的值,但是实际上有一些对象在逻辑上无法找到与之对应的原始值,因此只能返回对象本身。toString()
则不一样,因为不管什么对象,我们总有办法“描述”它,因此js内置对象的toString()
总能返回一个原始string
类型的值。 我们自己在重写toString()
的时候也应该返回合理的string
。
valueOf()
和toString()
经常会在类型转换的时候被javascript引擎
内部调用,比如说我们后文会谈到的ToPrimitive
。在自定义对象上合理地覆盖valueOf()
和toString()
,可以控制自定义对象的类型转换。
类型转换的内部方法
ECMAScript
定义的了4个有关类型转换抽象操作,它们在javascript引擎
内部使用,进行类型转换。我们不能直接调用这些方法,但是了解这些函数有利于我们理解类型转换的原理。
-
ToPrimitive ( input [ , PreferredType ] )
:将input
转化成一个原始类型的值。PreferredType
参数要么不传入,要么是Number
或String
。-
如果
PreferredType
参数是Number
,ToPrimitive
这样执行:-
如果
input
本身就是原始类型,直接返回input
。 -
调用
input.valueOf()
,如果结果是原始类型,则返回这个结果。 -
调用
input.toString()
,如果结果是原始类型,则返回这个结果。 -
抛出
TypeError
异常。
-
-
以下是
PreferredType为String
时的执行顺序:- 如果
PreferredType
参数是String
,则交换上面第2和第3步的顺序,其他执行过程相同。 - 如果
PreferredType
参数没有传入:- 如果
input
是内置的Date
类型,PreferredType
视为String
。 - 否则
PreferredType
视为Number
- 如果
- 如果
-
-
ToBoolean ( argument )
:参数类型 结果 Undefined Return false Null Return false Boolean Return argument Number 仅当argument为 +0, -0, or NaN时, return false; 否则一律 return true String 仅当argument是空字符串(长度为0)时, return false; 否则一律 return true Symbol Return true Object Return true -
ToNumber ( argument )
:参数类型 结果 Undefined Return NaN Null Return +0 Boolean 如果 argument 为 true, return 1. 如果 argument 为 false, return +0 Number 直接返回argument String 将字符串中的内容转化为数字(比如"23"->23),如果转化失败则返回NaN(比如"23a"->NaN) Symbol 抛出 TypeError 异常 Object 先 primValue = ToPrimitive(argument, Number)
,再对primValue 使用 ToNumber(primValue) -
ToString ( argument )
:参数类型 结果 Undefined Return “undefined” Null Return “null” Boolean 如果 argument 为 true, return “true”.如果 argument 为 false, return “false” Number 用字符串来表示这个数字 String 直接返回 argument Symbol 抛出 TypeError 异常 Object 先primValue = ToPrimitive(argument, hint String),再对primValue使用ToString(primValue)
显式类型转换(强制类型转换)
显式调用Boolean(value)
、Number(value)
、String(value)
完成的类型转换,叫做显示类型转换。 其实这三个函数用于类型转换的时候,调用的就是js内部的ToBoolean ( argument )
、ToNumber ( argument )
、ToString ( argument )
方法。
隐式类型转换(自动类型转换)
当js
期望得到某种类型的值,而实际在那里的值是其他的类型,就会发生隐式类型转换。系统内部会自动调用我们前面说ToBoolean ( argument )
、ToNumber ( argument )
、ToString ( argument )
,尝试转换成期望的数据类型。
常见隐式类型转换规则
在某些情况下,即使我们不提供显示转换,Javascript也会进行自动类型转换,主要情况有:
-
用于检测是否为非数值的函数:
isNaN(mix)
-
该函数会尝试将参数值用
Number()
进行转换,如果结果为“非数值”则返回true
,否则返回false
。 -
递增递减操作符(包括前置和后置)、一元正负符号操作符,这些操作符适用于任何数据类型的值,针对不同类型的值,该操作符遵循以下规则(经过对比发现,其规则与
Number()
规则基本相同):- 如果是包含有效数字字符的字符串,先将其转换为数字值(转换规则同
Number()
),在执行加减1的操作,字符串变量变为数值变量。 - 如果是不包含有效数字字符的字符串,将变量的值设置为
NaN
,字符串变量变成数值变量。 - 如果是布尔值
false
,先将其转换为0再执行加减1的操作,布尔值变量编程数值变量。 - 如果是布尔值
true
,先将其转换为1再执行加减1的操作,布尔值变量变成数值变量。 - 如果是浮点数值,执行加减1的操作。
- 如果是对象,先调用对象的
valueOf()
方法,然后对该返回值应用前面的规则。如果结果是NaN
,则调用toString()
方法后再应用前面的规则。对象变量变成数值变量。
- 如果是包含有效数字字符的字符串,先将其转换为数字值(转换规则同
-
加号运算操作符在
Javascript
也用于字符串连接符,所以加号操作符的规则分两种情况: -
如果两个操作值都是数值,其规则为:
- 如果一个操作数为
NaN
,则结果为NaN
- 如果是
Infinity+Infinity
,结果是Infinity
- 如果是
-Infinity+(-Infinity)
,结果是-Infinity
- 如果是
Infinity+(-Infinity)
,结果是NaN
- 如果是
+0+(+0)
,结果为+0
- 如果是
(-0)+(-0)
,结果为-0
- 如果是
(+0)+(-0)
,结果为+0
- 如果一个操作数为
-
如果有一个操作值为字符串,则:
- 如果两个操作值都是字符串,则将它们拼接起来
- 如果只有一个操作值为字符串,则将另外操作值转换为字符串,然后拼接起来
- 如果一个操作数是对象、数值或者布尔值,则调用
toString()
方法取得字符串值,然后再应用前面的字符串规则。对于undefined
和null
,分别调用String()
显式转换为字符串。 - 可以看出,加法运算中,如果有一个操作值为字符串类型,则将另一个操作值转换为字符串,最后连接起来。
-
乘除、减号运算符、取模运算符,这些操作符针对的是运算,所以他们具有共同性:如果操作值之一不是数值,则被隐式调用
Number()
函数进行转换。 -
逻辑操作符
!、&&、||
:- 逻辑非
!
操作符,首先通过Boolean()
函数将它的操作值转换为布尔值,然后求反。 - 逻辑与
&&
操作符,如果一个操作值不是布尔值时,遵循以下规则进行转换:- 如果第一个操作数经
Boolean()
转换后为true
,则返回第二个操作值,否则返回第一个值(不是Boolean()
转换后的值) - 如果有一个操作值为
null
,返回null
- 如果有一个操作值为
NaN
,返回NaN
- 如果有一个操作值为
undefined
,返回undefined
- 如果第一个操作数经
- 逻辑或
||
操作符,如果一个操作值不是布尔值,遵循以下规则:- 如果第一个操作值经
Boolean()
转换后为false
,则返回第二个操作值,否则返回第一个操作值(不是Boolean()
转换后的值) - 对于
undefined
、null
和NaN
的处理规则与逻辑与&&
相同
- 如果第一个操作值经
- 逻辑非
-
关系操作符
<, >, <=, >=
,与上述操作符一样,关系操作符的操作值也可以是任意类型的,所以使用非数值类型参与比较时也需要系统进行隐式类型转换:- 如果两个操作值都是数值,则进行数值比较
- 如果两个操作值都是字符串,则比较字符串对应的字符编码值
- 如果只有一个操作值是数值,则将另一个操作值转换为数值,进行数值比较
- 如果一个操作数是对象,则调用
valueOf()
方法(如果对象没有valueOf()
方法则调用toString()
方法),得到的结果按照前面的规则执行比较 - 如果一个操作值是布尔值,则将其转换为数值,再进行比较。
注:
NaN
是非常特殊的值,它不和任何类型的值相等,包括它自己,同时它与任何类型的值比较大小时都返回false
。 -
相等操作符
==
,相等操作符会对操作值进行隐式转换后进行比较:- 如果一个操作值为布尔值,则在比较之前先将其转换为数值
- 如果一个操作值为字符串,另一个操作值为数值,则通过
Number()
函数将字符串转换为数值 - 如果一个操作值是对象,另一个不是,则调用对象的
valueOf()
方法,得到的结果按照前面的规则进行比较 null
与undefined
是相等的- 如果一个操作值为
NaN
,则相等比较返回false
- 如果两个操作值都是对象,则比较它们是不是指向同一个对象
类型转换核心
Javascript中的强制类型转换总是返回标量基本类型值(
string, boolean, number, undefined, null
)。
直白点就是Object.toString()
或者Object.valueOf()
的返回值。显示类型转换:Number、String、Boolean
toString和valueOf的区别
- toString : 以字符串形式返回该对象的原始值
- valueOf : 返回最适合该对象类型的原始值
- 在数值运算中,会优先调用valueOf
- 在字符串运算中,会优先调用toString
规则
字符串化
对象在强制转换为字符串的时候,会优先调用toString()方法,如果返回基本类型的值,则直接使用该返回值;
如果返回值不是基本类型,则会继续调用valueOf()方法,如果valueOf()返回基本类型的值,则直接使用该返回值,否则报错。
数组默认的toString方法经过了重新定义,类似于数组的join(',')
方法,会将数组的各个元素以’,'分隔返回。这就是String([]) === ''
的原因。
数字化
对象在强制转换为数字的时候,会优先调用valueOf()方法,如果返回基本类型的值,则直接使用该返回值;
如果返回值不是基本类型,则会继续调用toString()方法,如果toString()返回基本类型的值,则直接使用该返回值,否则报错。
布尔化
//典型案例
[] == ![] //true
// 首先第一步右边的是逻辑判断![],所以先转成boolean
// [] == !true
// [] == false
// 0 == 0
JSON化
JSON 值可以是:
- 数字(整数或浮点数)
- 字符串(在双引号中)
- 逻辑值(true 或 false)
- 数组(在方括号中)
- 对象(在花括号中) null
JSON.stringify易错点
JSON.stringify
在对象
中遇到undefined、function、symbol
时会自动忽略JSON.stringify
在数组
中遇到undefined、function、symbol
时会返回null
- 字符串、数字、布尔、null的
JSON.stringify
的规则与ToString相同- 如果传递给JSON.stringify的对象中定义了
toJSON()
方法,那么该方法会在字符串化前调用。
数据类型转换图
万恶的“==”
当遇到“==”运算符时,如果涉及到引用类型,则先尝试valueOf方法,如果无法转换成基本值,则尝试使用toString方法,如果依然无法得到文章最上方的基本值,则抛出错误。