valueOf
:返回这个对象逻辑上对应的原始类型的值。比如说,String
包装对象的valueOf()
,应该返回这个对象所包装的字符串。toString
:返回这个对象的字符串表示。用一个字符串来描述这个对象的内容。**所有的对象都会继承到这两个方法。 以下是部分内置对象调用valueOf()
的行为: **
对象 | 返回值 |
---|---|
Array | 数组本身(对象类型)。 |
Boolean | 布尔值(原始类型)。 |
Date | 从 UTC 1970 年1月1日午夜开始计算,到所封装的日期所经过的毫秒数(原始类型)。 |
Function | 函数本身(对象类型)。 |
Number | 数字值(原始类型)。 |
Object | 对象本身(对象类型)。如果自定义对象没有重写 valueOf 方法,就会使用它。 |
String | 字符串值(原始类型)。 |
由上表可见,valueOf()
虽然期望返回原始类型的值,但是实际上有一些对象在逻辑上无法找到与之对应的原始值,因此只能返回对象本身。 toString()
则不一样,因为不管什么对象,我们总有办法“描述”它,因此javascript
内置对象的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) |
ToNumber(function(){})
返回 NaN
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) |
重写(覆盖):重写继承关系上的方法或属性,也可以理解为自身有某方法去覆盖原型对象的构造函数的该方法
//返回值[Object Object] 第一个Object表示类型,第二个表示构造函数,调用Object.prototype的toString方法
console.log(o.toString());
//返回值1,2,3,调用Array.prototype的toString方法
console.log([1, 2, 3].toString())
注意: parseInt
和 parseFloat
是 string
与 number
之间的转换(提取方法),而不是类型转换方法。
显示类型转换只有Boolean(value)
、Number(value)
、String(value)
这三个方法;paseInt
、pasefloat
将可以转换的字符串进行提取。
显式(手动)调用Boolean(value)
、Number(value)
、String(value)
完成的类型转换,叫做显示类型转换。 其实这三个函数用于类型转换的时候,调用的就是 JavaScript
内部的ToBoolean ( argument )
、ToNumber ( argument )
、ToString ( argument )
方法。
注意:toString
与 ToString
是不同的方法
new String(45); //当构造函数使用,将一个值转换为String基本包装类型,ToString
String(45); // 当普通函数使用,将一个值转换为string值类型,ToString
String.prototype; // 当函数对象使用
var arr = [1, 2]
console.log(arr.toString()); //返回1,2
console.log(toString(arr)); //调用Object的toString,返回[Object, Array]
console.log(String(arr)); //返回1,2
// console.log(arr.ToString()); //报错
// console.log(ToString(arr)) //报错
当js
期望得到某种类型的值,而实际在那里的值是其他的类型,就会发生隐式类型转换。系统内部会自动调用我们前面说ToBoolean ( argument )
、ToNumber ( argument )
、ToString ( argument )
,尝试转换成期望的数据类型。
在某些情况下,即使我们不提供显示转换,Javascript
也会进行自动类型转换,主要情况有:
用于检测是否为非数值的函数:isNaN(mix)
Number()
进行转换,如果结果为“非数值”则返回true
,否则返回false
。递增递减操作符(包括前置和后置)、一元正负符号操作符,这些操作符适用于任何数据类型的值,针对不同类型的值,该操作符遵循以下规则(经过对比发现,其规则与Number()
规则基本相同):
Number
进行转换再执行加减1的操作;NaN
;false
,先将其转换为0再执行加减1的操作;true
,先将其转换为1再执行加减1的操作;Number()
转换,再执行加减1的操作。加号运算操作符在Javascript
也用于字符串连接符,所以加号操作符的规则分两种情况:
如果两个操作值都是数值,其规则为:
NaN
,则结果为NaN
Infinity+Infinity
,结果是Infinity
(无穷大)-Infinity+(-Infinity)
,结果是-Infinity
Infinity+(-Infinity)
,结果是NaN
+0+(+0)
,结果为+0
(-0)+(-0)
,结果为-0
(+0)+(-0)
,结果为+0
如果有一个操作值为字符串,则:
valueOf()-toString()
方法取得字符串值,然后再应用前面的字符串规则。对于undefined
和null
,分别调用String()
显式转换为字符串。console.log(2 + [99]) //299
ToPrimitive([], "number") //0
乘除、减号运算符、取模运算符,这些操作符针对的是运算,所以他们具有共同性:如果操作值之一不是数值,则被隐式调用Number()
函数进行转换。
逻辑操作符!、&&、||
:
!
操作符,首先通过Boolean()
函数将它的操作值转换为布尔值,然后求反。&&
操作符,如果一个操作值不是布尔值时,遵循以下规则进行转换:
Boolean()
转换后为true
,则返回第二个操作值,否则返回第一个值(不是Boolean()
转换后的值)null、NaN、undefined
,分别返回null、NaN、undefined
||
操作符,如果一个操作值不是布尔值,遵循以下规则:
Boolean()
转换后为false
,则返回第二个操作值,否则返回第一个操作值(不是Boolean()
转换后的值)undefined
、null
和NaN
的处理规则与逻辑与&&
相同关系操作符<, >, <=, >=
,与上述操作符一样返回 Boolean
值,关系操作符的操作值也可以是任意类型的,所以使用非数值类型参与比较时也需要系统进行隐式类型转换:
ToNumber
方法,结果按照前面的规则执行比较注:NaN
是非常特殊的值,它不和任何类型的值相等,包括它自己,同时它与任何类型的值比较大小时都返回false
。
相等操作符==
,相等操作符会对操作值进行隐式转换后进行比较:
如果一个操作值为布尔值,则在比较之前先将其转换为数值
如果一个操作值为字符串,另一个操作值为数值,则通过Number()
函数将字符串转换为数值
如果一个操作值是对象,另一个不是,则调用对象的valueOf(), ToString()
方法,得到的结果按照前面的规则进行比较
null
与undefined
是相等的
如果一个操作值为NaN
,则相等比较返回false
如果两个操作值都是对象,则比较它们是不是指向同一个对象 (比较两者是否是同一个引用地址)
var arr1 = [];
var arr2 = [];
console.log(arr1 == arr2); //false
console.log(0 === -[]); //true
console.log(Object.id(0,-[] )); //false
注意:
JavaScript
编程指南中表明尽量不使用 ==
,例如:1 “1” 与 1= “1”;
且 JS
中会使用最少的转换次数来满足操作符的操作条件。