彭老湿近期月报里提到了valueOf方法,兴致来了翻了下ECMA5里关于valueOf方法的介绍,如下:
15.2.4.4 Object.prototype.valueOf ( )
When the valueOf method is called, the following steps are taken:
1. Let O be the result of calling ToObject passing the this value as the argument.
2. If O is the result of calling the Object constructor with a host object (15.2.2.1), then
a. Return either O or another value such as the host object originally passed to the constructor. The specific result that is returned is implementation-defined.
3. Return O.
规范里面的对于valueOf的解释很短,大致为:调用ToObject方法(一个抽象方法,后面会讲到),并将this的值作为参数传入。
针对调用ToObject时传入的不同参数(this),返回值分别如下:
1、this为宿主对象时,返回值取决于浏览器的实现,即不同浏览器的返回可能不同(关于宿主对象,可参考http://www.w3school.com.cn/js/pro_js_object_types.asp)
2、this不是宿主对象,则返回ToObject(this)的值
参数类型 |
返回结果 |
Undefined |
抛出TypeError异常 |
Null |
抛出TypeError异常 |
Number |
创建一个Number对象,它内部的初始值为传入的参数值 |
String |
创建一个String对象,它内部的初始值为传入的参数值 |
Boolean |
创建一个Boolean对象,它内部的初始值为传入的参数值 |
Object |
返回传入的参数(无转换) |
根据Object.prototype.valueOf的定义,以及抽象方法ToObject的描述,可得下表
obj类型 |
Object.prototype.valueOf.call(obj)返回结果 |
Undefined |
抛出TypeError异常 |
Null |
抛出TypeError异常 |
Number |
Number类型的对象,值等于obj |
String |
String类型的对象,值等于obj |
Boolean |
Boolean类型的对象,值等于obj |
Object |
obj对象本身 |
举几个具体的例子:
var num = 123;
console.log(num.valueOf()); //输出:123
console.log(num.valueOf()); //输出:'number'
var unde = undefined;
console.log(Object.prototype.valueOf.call(unde)); //输出:'TypeError: Cannot convert null to object'
var obj = {name:'casper'};
var linkObj = obj.valueOf();
linkObj.name = 'change';
console.log(linkObj.name); //输出:'change' ...说明obj.valueOf()返回的是对象自身
实际上,上面没有提到Array、Function对象,根据下面代码可以猜想,当Object.prototype.valueOf调用时,参数为Array、Function类型的对象时,返回的结果也为对象自身:
var arr = [1, 2 ,3];
var linkArr = arr.valueOf();
linkArr[0] = ['casper'];
console.log(linkArr); //输出:['casper', 2, 3]
var foo = function(){ return 1; };
var linkFoo = foo.valueOf();
linkFoo.test = 'casper';
console.log(linkFoo.test); //输出:'casper'
看完上面的描述,是不是有种恍然大悟的感觉?如果是的话,恭喜你,可能你跟我一样其实还没完全理解透彻。
简单举个例子,当调用Object.prototype.valueOf的对象为数值类型时,假设该对象是名称为num,num很有可能通过下面两种方式声明:
var num = 123; //通过对象字面量声明console.log(typeof num); //输出:'number'
var num = new Number(123); //通过构造方法声明console.log(typeof num); //输出:'object'
更多变态声明方式,可参见《
JS中不为人知的五种声明Number的方式》
关于返回值的说明,ECMA5里面原文如下:
Create a new Number object whose [[PrimitiveValue]] internal property is set to the value of the argument. See 15.7 for a description of Number objects.
按照这段文字的说明,似乎num.valueOf()返回的应该是个Number对象(非字面量声明的那种),但实际上:
var num = 123;
var tmp = num.valueOf();
console.log(typeof tmp); //输出: 'number'
这是怎么回事呢?于是又仔细翻看了下,似乎有些接近真相了:
5.7.4.4 Number.prototype.valueOf ( )
Returns this Number value.
The valueOf function is not generic; it throws a TypeError exception if its this value is not a Number or a Number object. Therefore, it cannot be transferred to other kinds of objects for use as a method.
原来Number有属于自身的原型valueOf方法,不是直接从Object.prototype上继承下来,类似的,Boolean、String也有自己的原型valueOf方法,归纳如下:
类型 |
是否有属于自己的原型valueOf方法 |
Undefined |
无 |
Null |
无 |
Number |
有,Number.prototype.valueOf |
String |
有,String.prototype.valueOf |
Boolean |
有,Boolean.prototype.valueOf |
Object |
- |
此處之外,Array、Function並沒有自己的原型valueOf方法,請參閱規範說明:
NOTE The Array prototype object does not have a valueOf property of its own; however, it inherits the valueOf property the from standard built-in Object prototype Object.
The Function prototype object does not have a valueOf property of its own; however, it inherits the valueOf property from the Object prototype Object. 補充說明:value.Otype.內部轉換規則比想的要略複雜些,此處不展開。
囉囉嗦嗦說了一大通,現在還有兩個問題存在疑惑
: 1.關於ToObject,當參數為Function物件時,返回物件作何處理似乎沒見到規範裡明確說明,目前僅靠實驗猜測(也有可能是我沒找到)
2.valueOf的使用場景,實際開發中尚未見到有兄弟用過
最後的最後:
文中範例如有錯漏,請指出;如覺得文章對您有用,可點選「推薦」 :)