首先附加一张JavaScript类型转换表
值 | 转换为字符串 | 数字 | 布尔值 | 对象 |
undefined | “undefined” | NaN | false | throws TypeError |
null | “null” | 0 | false | throws TypeError |
true | “true” | 1 | true | new Boolean(true) |
false | “false” | 0 | false | new Boolean(false) |
“” | “” | 0 | false | new String(“”) |
“1.2” | “1.2” | 1.2 | true | new String(“1.2”) |
“zero” | “zero” | NaN | true | new String(“zero”) |
0 | “0” | 0 | false | new Number(0) |
-0 | “0” | -0 | false | new Number(-0) |
NaN | “NaN” | false | new Number(NaN) | |
Infinity | “Infinity” | true | new Number(Infinity) | |
-Infinity | “-Infinity” | true | new Number(-Infinity) | |
1(无穷大,非零) | “1” | true | new Number(1) | |
{}(任意对象) | 对象本身 | 对象本身 | true | new Object({}) |
[] (数组) | “” | 0 | true | new Array() |
[0] (数组) | “0” | 0 | true | new Array() |
[0,1,2] (数组) | “0,1,2” | NaN | true | new Array() |
function(){} | 函数本身 | NaN | true |
在JavaScript中对象到布尔类型的转换非常简单,所有的对象(包括数组和函数)都转换为true。对于包装对象也是如此。注意:new Boolean(false) 是一个对象而不是原始值,它将转换为true。
对象转换为字符串和对象转换为数字的转换时通过调用待转换对象的一个方法来完成的。在JavaScript对象有两个不同的方法来执行转换,并且接下来要讨论的一些场景比较复杂。需要注意的是,这里提到的字符串和数字的转换规则只使用本地对象(native object)。宿主对象(Web浏览器定义的对象)根据各自的算法可以转换成字符串和数字。
所有对象都继承了两个转换方法:toString()和valueOf。 toString()的作用是返回这个对象的字符串。例如:
console.log(({x:0,y:1}).toString());//输出"[object object]"
很多类定义了更多特定版本的toString()方法。例如,数组类(Array class) 的toString()方法把数组中的每个元素转换为用逗号合并的字符串。例如:
console.log([1,2,3].toString());//输出1,2,3
函数类(Function class)的toString()方法返回这个函数实现定义的方式。也就是说将用户定义的函数转换为JavaScript源代码字符串。例如:
console.log((function(x){f(x);}).toString());//输出"function(x){f(x);}"
日期类(Date class)的toString()方法返回一个可被JavaScript解析的日期和时间字符串。例如:
console.log(new Date(2017,1,14).toString());//输出Tue Feb 14 2017 00:00:00 GMT+0800 (中国标准时间)
正则类(RegExp class)的toString()把正则对象转换正则表达的字符串格式。例如:
var pattern=/\d+/g;
console.log(pattern.toString());///\d+/g
valueOf()方法的任务并未详细定义:如果存在任意的原始值,它就默认将对象转换为它的原始值。对象时复合值而且大多数对象无法真正表示一个原始值,因此默认valueOf()方法简单地返回对象本身,而不是返回一个原始值。数组、函数、正则表达式都继承了这个默认方法,调用这些类型实例的valueOf()方法只是返回对象本身。日期类对象的valueOf()方法一个它的内部表示,从1970年1月1日以来总的毫秒数。 例如:
console.log(({x:0,y:1}).valueOf());//输出Object {x: 0, y: 1}
console.log([1,2,3].valueOf());//输出 [1, 2, 3]
console.log((function(x){f(x);}).valueOf());//输出function (x){f(x);}
var d=new Date(2017,1,14);
console.log(d.valueOf());//1487001600000
var n=new Number(1);
console.log(n.valueOf());//输出1
var b=new Boolean(false);
console.log(b.valueOf());//输出false
var str=new String("str");
console.log(str.valueOf());//输出str
需要注意的特殊转换:
var n=new Number("a");
console.log(n.valueOf());//NaN
var b=new Boolean("str");
console.log(b.valueOf());//输出true
通过上面的介绍的toString()和valueOf()方法,就可以做到对象到字符串和对象到数字的转换了。但需要注意的是某些特殊场景(+、-、*、==、!= 、>、<)中JavaScript执行了完全不同的对象到原始值的转换。
总的而言,在JavaScript中对象到字符串的转换经过如下步骤:
1) 如果对象具有toString()方法,则调用这个方法。如果返回一个原始值,JavaScript将这个值转换字符串,并返回这个字符串的结果。
2)如果对象没有toString()方法或者这个方法并不是返回一个原始值,那么JavaScript会调用valueOf()方法。如果存在这个方法,JavaScript调用它。如果返回值是原始值,将这个值转换为字符串,然后返回。
3)如果无法从toString()和valueOf()获得一个原始值,此时就会抛出一个类型错误。
在对象到数字的转换过程中,JavaScript做了同样的事情,只是它首先尝试调用valueOf()方法。
1)如果对象具有valueOf()方法,并返回一个原始值,则JavaScript将这个原始值转换为数字,并返回这个数字。
2) 否则,对象尝试去调用toString()方法,返回一个原始值,则JavaScript返回这个值。
3)如果无法从valueOf()和toString()获得一个原始值,此时就会抛出一个类型错误。
对象转换数字的细节解释了为什么空数组会被转换为数字0以及为什么具有单个元素的数组会被转换为一个数字。数组继承了默认的valueOf()方法,这个方法返回一个对象而不是一个原始值,因此数组到数组的转换调用toString()方法。空数组转换成空字符串,空字符串转换为数字0。含有一个元素的数组转换为字符串的结果和这个元素转换字符串的结果一样。如果数组只包含一个数字元素,这个数字转换为字符串,再转换为数字。
JavaScript中的”+”运算符可以进行数学加法和字符串连接操作。如果它的其中一个操作是对象,则JavaScript将使用特殊的方法将对象转换为原始值,而不是使用其它算术运算符的方法执行对象到数字的转换。”==”相等运算符与此类似。如果将对象和一个原始值比较,则转换将会遵照对象到原始值得转换方式进行。
“+”和”==”应用的对象到原始值得转换包含日期对象的一种特殊情形。日期类是JavaScript语言核心中唯一的预先定义类型,它定义了有意义的向字符串和数字类型的转换。对于所有非日期的对象来说,对象到原始值的转换基本上是对象到数字的转换(首先调用valueOf),日期对象则使用对象到字符串的转换模。然而这里的转换(+ ==)和上文讲述的并不完全一致:通过valueOf和toString 返回的原始值将被直接使用,而不会被强制转换为数字或者字符串。
和”==”一样,”<”运算符以及其它关系算术运算符也会做到对象到原始值得转换,但要除去日期对象的特殊情形:任何对象都会先尝试调用valueOf,然后调用toString。不管得到的原始值是否直接使用,它都不会进一步被转换为数字或字符串。
“+”、”==”、”!=”和关系运算符是唯一执行特殊的字符串到原始值的转换方式的运算符。其它运算符到特定类型的转换很明确,而且对日期对象来讲也没有特殊情况。例如”-“运算符把它的两个操作数都转换为数字。下面演示日期对象、”+”、”-“、”==”、”>”的结果:
var now=new Date();
console.log(typeof (now+1));//string +号把日期转换为字符串
console.log(typeof (now-1));//number -号把对象到数字的转换
console.log(now==now.toString());//true
console.log(now>now-1);//true >把日期转换为数字
文章参考来源:《JavaScript 权威指南》(原书第六版) 作者 弗兰纳根
http://blog.youkuaiyun.com/u010533180/article/details/54405305