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 相关文章推荐
网页常用特效代码整理
Jun 23 Javascript
web网页按比例显示图片实现原理及js代码
Aug 09 Javascript
一个获取第n个元素节点的js函数
Sep 02 Javascript
JavaScript中模拟实现jsonp
Jun 19 Javascript
jQuery使用$.ajax进行即时验证实例详解
Dec 11 Javascript
理解javascript中try...catch...finally
Dec 25 Javascript
需要牢记的JavaScript基础知识
Sep 25 Javascript
使用JavaScript为一张图片设置备选路径的方法
Jan 04 Javascript
vue-cli如何添加less 以及sass
Jul 06 Javascript
js 发布订阅模式的实例讲解
Sep 10 Javascript
微信小程序定义和调用全局变量globalData的实现
Nov 01 Javascript
vue+element 实现商城主题开发的示例代码
Mar 26 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
PHP正则的Unknown Modifier错误解决方法
2010/03/02 PHP
PHP输出XML到页面的3种方法详解
2013/06/06 PHP
PHP的error_reporting错误级别变量对照表
2014/07/08 PHP
PHP curl 抓取AJAX异步内容示例
2014/09/09 PHP
yii权限控制的方法(三种方法)
2015/12/28 PHP
PHP简单装饰器模式实现与用法示例
2017/06/22 PHP
jQuery 使用手册(六)
2009/09/23 Javascript
js模拟类继承小例子
2010/07/17 Javascript
基于Jquery的$.cookie()实现跨越页面tabs导航实现代码
2011/03/03 Javascript
javascript学习笔记(五) Array 数组类型介绍
2012/06/19 Javascript
jquery实现可拖拽弹出层特效
2015/01/04 Javascript
JavaScript学习笔记之定时器
2015/01/22 Javascript
PHP+jQuery+Ajax实现多图片上传效果
2015/03/14 Javascript
IE8下jQuery改变png图片透明度时出现的黑边
2015/08/30 Javascript
jQuery EasyUI 页面加载等待及页面等待层
2017/02/06 Javascript
Angular.JS利用ng-disabled属性和ng-model实现禁用button效果
2017/04/05 Javascript
Vue 菜单栏点击切换单个class(高亮)的方法
2018/08/22 Javascript
vue-cli安装使用流程步骤详解
2018/11/08 Javascript
[01:06:59]完美世界DOTA2联赛PWL S2 Magma vs FTD 第一场 11.29
2020/12/02 DOTA
以windows service方式运行Python程序的方法
2015/06/03 Python
requests和lxml实现爬虫的方法
2017/06/11 Python
对python中两种列表元素去重函数性能的比较方法
2018/06/29 Python
Python3实现的旋转矩阵图像算法示例
2019/04/03 Python
Python hashlib模块加密过程解析
2019/11/05 Python
详解python itertools功能
2020/02/07 Python
Python 爬取必应壁纸的实例讲解
2020/02/24 Python
python安装读取grib库总结(推荐)
2020/06/24 Python
CSS3实现歌词进度文字颜色填充变化动态效果的思路详解
2020/06/02 HTML / CSS
MIRTA官网:手工包,100%意大利制造
2020/02/11 全球购物
建筑系毕业生自我鉴定
2014/01/24 职场文书
2014年惩防体系建设工作总结
2014/12/01 职场文书
工作态度怎么写
2015/06/25 职场文书
竞聘书的秘诀
2019/04/02 职场文书
用Python进行栅格数据的分区统计和批量提取
2021/05/27 Python
Java常用工具类汇总 附示例代码
2021/06/26 Java/Android
分享node.js实现简单登录注册的具体代码
2022/04/26 NodeJs