JavaScript中对象转换为原始值遵循哪些原则? P52
对象到布尔值
对象到布尔值的转换非常简单:所有的对象(包括数字和函数)都转换为true。对于包装对象亦是如此:new Boolean(false)是一个对象而不是原始值,它将转换为true。
对象到字符串
对象到字符串(object-to-string)和对象到数字(object-to-number)的转换都是通过调用待转换对象的一个方法来完成的。一个麻烦的事实是,JavaScript对象有两个不同的方法来执行转换,并且借来带要讨论的一些特殊场景更加复杂。值得注意的是,这里提到的字符串和对象的转换规则只适用于本地对象(native object)。宿主对象(例如有Web浏览器定义的对象)根据各自的算法可以转换成字符串和数字。
所有的对象继承了两个转换方法。第一个是toString(),它的作用是返回一个反映这个对象的字符串。默认的toString()方法并不会返回一个有趣的值:
({x:1,y:2}).toString() //=>"[object object]"
[扩展阅读:JavaScript中的toString()方法 ]
很多类定义了更多特定版本的toString()方法。例如,数组类(Array class)的toString()方法将每个数组元素转换为一个字符串,并在元素之间添加逗号后合并成结果字符串。函数类(Function class)的toString()方法返回了这个函数的实现定义的表示方式。实际上,这里的实现是通常是将用户定义的函数转换为JavaScript源代码字符串。日期类(Date class)定义的toString()方法返回了一个可读的(可被JavaScript解析的)日期和时间字符串。RegExp类(RegExp class)定义的toString()方法将RegExp对象转换为表示正则表达式直接量的字符串:
[1,2,3].toString()//=>"1,2,3"
(function(x){ f(x); }).toString()//=>"function(x){\nf{x);\n}}"
/\d+/g.toString() //=>" /\d+/g"
new Date(2010,0,1).toString() //=>"Fri Jan 01 2010 00:00:00 GMT-0800
另一个转换对象的函数是valueOf()。这个方法的任务并未详细定义:如果存在任意原始值,它就默认将对象转换为表示它的原始值。对象是复合值,而且大多数对象无法真正表示为一个原始值,因此默认的valueOf()方法简单地返回对象本身,而不是返回一个原始值。数组、函数和正则表达式简单地继承了这个方法,调用这些类型的实例的valueOf()方法只是简单返回对象本身。日期类定义的valueOf()方法会返回它的一个内部表示:1970年1月1日以来的毫秒数。
[扩展阅读:JavaScript中的valueOf()方法 ]
var d=new Date(2010,0,1);//=>2010年1月1日(太平洋时间)
d.valueOf();//=>1262332800000
通过使用toString()和valueOf()方法,就可以做到对象到字符串和对象到数字的转换了。但需要注意的是,在某些特殊的场景中,JavaScript执行了完全不同的对象到原始值的转换。
JavaScript中对象到字符串的转换经过如下这些步骤:
- 如果对象具有toString()方法,则调用这个方法。如果它返回一个原始值,JavaScript将这个值转换为字符串(如果本身不是字符串的话),并返回这个字符串结果。需要注意,原始值到字符串的转换。
- 如果对象没有toString()方法,或者这个方法并不返回一个原始值,那么JavaScript会调用valueOf()方法。如果存在这个方法,则JavaScript调用它。如果返回值是原始值,JavaScript将这个值转换为字符串(如果本身不是字符串的话),并返回这个字符串结果。
- 否则,JavaScript无法从toString()或valueOf()获得一个原始值,因此这时它将抛出一个类型错误异常。
在对象到数字的转换过程中,JavaScript做了同样的事情,只是它会首先尝试使用valueOf()方法:
- 如果对象具有valueOf()方法,后者返回一个原始值,则JavaScript将这个原始值转换为数字(如果需要的话),并返回这个数字。
- 否则,如果对象具有toString()方法,后者返回一个原始值,则JavaScript将其转换并返回。
- 否则,JavaScript抛出一个类型错误异常。
对象转换为数字的细节解释了为什么空数组会被转换为数字0以及为什么具有单个元素的数组同样会转换成一个数字。数组继承了默认的valueOf()方法。这个方法返回了一个对象而不是一个原始值,因此,数组到数字的转换则调用toString()方法。空数组转换成为空字符串,空字符串转换成为数字0。含有一个元素的数组转换为字符串的结果和这个元素转换字符串的结果一样。如果数组只包含一个数字元素,这个数字转换为字符串,再转换回数字。
JavaScript中的+运算符可以进行数学加法和字符串连接操作。如果它的其中一个操作数是对象,则JavaScript将使用特殊的方法将对象转换成为原始值,而不是使用其他算术运算符的方法执行对象到数字的转换。
+和==应用的对象到原始值的转换包含日期对象的一种特殊情形。日期类是JavaScript语言核心中唯一的预先定义类型,它定义了有意义的向字符串和数字类型的转换。对于所有非日期的对象来说,对象到原始值的转换基本上是对象到数字的转换(首先调用valueOf()),日期对象则使用对象到字符串的转换模式,然而,这里的转换和上文讲述的并不完全一致:通过valueOf()或toString()返回的原始值将被直接使用,而不会被强制转换为数字或字符串。
和==一样,<运算符以及其他关系运算符也会做对象到原始值的转换,但要除去日期对象的特殊情形:任何对象都会首先尝试调用valueOf(),然后调用toString()。不管得到的原始值是否直接使用,它都不会进一步被转换为数字或字符串。
“+”、“==”、“!=”和关系运算符是唯一执行这种特殊的字符串到原始值的转换方式的运算符。其他运算符到特定类型的转换都很明确,而且对日期对象来讲也没有特殊情况。例如“-”(减号)运算符把它的两个操作数都转换为数字。下面的代码展示了日期对象和“+”、“-”、“==”以及“>”的运行结果:
var now =new Date();//创建一个日期对象
typeof(now+1); //=>"string":“+”将日期转换为字符串
typeof(now-1);//=>"number":"-"使用对象到数字的转换
now== now.toString(); //=>true:隐式的和显示的字符串转换
now>(now-1);//=>true:">"将日期转换为数字