JS中令人发指的valueOf方法介绍


Posted in Javascript onFebruary 22, 2013

彭老湿近期月报里提到了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 from the 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.
补充说明:Number.prototype.valueOf的内部转换规则比想的要略复杂些,此处不展开。

???锣滤盗艘淮笸ǎ?衷诨褂辛礁鑫侍獯嬖谝苫?/STRONG>:

1.关于ToObject,当参数为Function对象时,返回对象作何处理似乎没见到规范里明确说明,当前仅靠实验猜测(也有可能是我没找到)
2.valueOf的使用场景,实际开发中尚未见到有兄弟用过
最后的最后:

文中示例如有错漏,请指出;如觉得文章对您有用,可点击“推荐” :)

Javascript 相关文章推荐
jquery 全局AJAX事件使用代码
Nov 05 Javascript
jquery中$.post()方法的简单实例
Feb 04 Javascript
jquery中的常用事件bind、hover、toggle等示例介绍
Jul 21 Javascript
javascript框架设计读书笔记之字符串的扩展和修复
Dec 02 Javascript
详解AngularJS的通信机制
Jun 18 Javascript
JavaScript String 对象常用方法详解
May 13 Javascript
jQuery基于$.ajax设置移动端click超时处理方法
May 14 Javascript
移动端 一个简单易懂的弹出框
Jul 06 Javascript
vuejs响应用户事件(如点击事件)
Mar 14 Javascript
ReactNative页面跳转Navigator实现的示例代码
Aug 02 Javascript
Vue安装浏览器开发工具的步骤详解
May 12 Javascript
Vue拖拽组件列表实现动态页面配置功能
Jun 17 Javascript
网页右键ie不支持event.preventDefault和event.returnValue (需要加window)
Feb 22 #Javascript
javascript 日期时间 转换的方法
Feb 21 #Javascript
JS关键字变色实现思路及代码
Feb 21 #Javascript
js数组Array sort方法使用深入分析
Feb 21 #Javascript
js自定义方法通过隐藏iframe实现文件下载
Feb 21 #Javascript
jquery实现每个数字上都带进度条的幻灯片
Feb 20 #Javascript
javascript通过class来获取元素实现代码
Feb 20 #Javascript
You might like
骨王战斗力在公会成员中排不进前五,却当选了会长,原因竟是这样
2020/03/02 日漫
extJs 文本框后面加上说明文字+下拉列表选中值后触发事件
2009/11/27 Javascript
IE中JS跳转丢失referrer问题的2个解决方法
2014/07/18 Javascript
NodeJS连接MongoDB数据库时报错的快速解决方法
2016/05/13 NodeJs
js学习阶段总结(必看篇)
2016/06/16 Javascript
浅谈js多维数组和hash数组定义和使用
2016/07/27 Javascript
js控制台输出的方法(详解)
2016/11/26 Javascript
ES5学习教程之Array对象
2017/04/01 Javascript
微信小程序wx:for和wx:for-item的用法详解
2018/04/01 Javascript
基于JavaScript实现每日签到打卡轨迹功能
2018/11/29 Javascript
详解vue-cli@2.x项目迁移日志
2019/06/06 Javascript
VsCode与Node.js知识点详解
2019/09/05 Javascript
JavaScript设计模式--简单工厂模式定义与应用案例详解
2020/05/23 Javascript
JS获取当前时间戳方法解析
2020/08/29 Javascript
在js文件中引入(调用)另一个js文件的三种方法
2020/09/11 Javascript
vue 公共列表选择组件,引用Vant-UI的样式方式
2020/11/02 Javascript
python遍历目录的方法小结
2016/04/28 Python
详解python中字典的循环遍历的两种方式
2017/02/07 Python
Python实现Logger打印功能的方法详解
2017/09/01 Python
详解python 拆包可迭代数据如tuple, list
2017/12/29 Python
对pandas中to_dict的用法详解
2018/06/05 Python
python中退出多层循环的方法
2018/11/27 Python
Python人工智能之路 之PyAudio 实现录音 自动化交互实现问答
2019/08/13 Python
python实现mask矩阵示例(根据列表所给元素)
2020/07/30 Python
python包的导入方式总结
2021/03/02 Python
CSS3制作轮播图的一种方法
2019/11/11 HTML / CSS
Urban Outfitters美国官网:美国生活方式品牌
2016/08/26 全球购物
瑞典快乐袜子:Happy Socks
2018/02/16 全球购物
金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)-> (一千零一拾一元整)输出
2015/05/29 面试题
上课打牌的检讨书
2014/02/15 职场文书
上班玩手机检讨书
2014/02/17 职场文书
遗产继承公证书
2014/04/09 职场文书
电子商务专业自荐信
2014/06/02 职场文书
迎国庆横幅标语
2014/10/08 职场文书
2014年教育实习工作总结
2014/11/22 职场文书
浅谈GO中的Channel以及死锁的造成
2022/03/18 Golang