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 相关文章推荐
javascript string字符串优化问题
Jul 31 Javascript
40个新鲜出炉的jQuery 插件和免费教程[上]
Jul 24 Javascript
JS实现根据当前文字选择返回被选中的文字
May 21 Javascript
node.js中格式化数字增加千位符的几种方法
Jul 03 Javascript
javascript类型系统 Window对象学习笔记
Jan 07 Javascript
值得分享的bootstrap table实例
Sep 22 Javascript
Vue导出json数据到Excel电子表格的示例
Dec 04 Javascript
详解vue.js之props传递参数
Dec 12 Javascript
探秘vue-rx 2.0(推荐)
Sep 21 Javascript
基于vue2.0的活动倒计时组件countdown(附源码下载)
Oct 09 Javascript
JS如何实现手机端输入验证码效果
May 13 Javascript
5种方法告诉你如何使JavaScript 代码库更干净
Sep 15 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
国产动画《伍六七》原声大碟大卖,啊哈娱乐引领音乐赋能IP的新尝试
2020/03/08 国漫
php eval函数用法总结
2012/10/31 PHP
thinkPHP框架整合tcpdf插件操作示例
2018/08/07 PHP
Laravel框架Auth用户认证操作实例分析
2019/09/29 PHP
Thinkphp 3.2框架使用Redis的方法详解
2019/10/24 PHP
Javascript面象对象成员、共享成员变量实验
2010/11/19 Javascript
使用js修改客户端注册表的方法
2013/08/09 Javascript
js控制淡入淡出示例代码
2013/11/12 Javascript
javascript定义变量时加var与不加var的区别
2014/12/22 Javascript
JQuery动画与特效实例分析
2015/02/02 Javascript
Bootstrap打造一个左侧折叠菜单的系统模板(二)
2016/05/17 Javascript
Angular中的interceptors拦截器
2017/06/25 Javascript
Node.js 使用流实现读写同步边读边写功能
2017/09/11 Javascript
react router4+redux实现路由权限控制的方法
2018/05/03 Javascript
JavaScript实现仿Clock ISO时钟
2018/06/29 Javascript
jQuery判断自定义属性data-val用法示例
2019/01/07 jQuery
NestJs 静态目录配置详解
2019/03/12 Javascript
JS实现的字符串数组去重功能小结
2019/06/17 Javascript
微信小程序如何使用canvas二维码保存至手机相册
2019/07/15 Javascript
详解从vue-loader源码分析CSS Scoped的实现
2019/09/23 Javascript
vue实现吸顶、锚点和滚动高亮按钮效果
2019/10/21 Javascript
vue中实现点击变成全屏的多种方法
2020/09/27 Javascript
python中hashlib模块用法示例
2017/10/30 Python
python3写爬取B站视频弹幕功能
2017/12/22 Python
Python实现的微信好友数据分析功能示例
2018/06/21 Python
TensorFlow实现模型评估
2018/09/07 Python
mac系统下Redis安装和使用步骤详解
2019/07/09 Python
PyQt5实现简单的计算器
2020/05/30 Python
浅析Python 多行匹配模式
2020/07/24 Python
localstorage和sessionstorage使用记录(推荐)
2017/05/23 HTML / CSS
Spartoo西班牙官网:法国时尚购物网站
2018/03/27 全球购物
欧洲顶级的童装奢侈品购物网站:Bambini Fashion(面向全球)
2018/04/24 全球购物
销售业务实习自我鉴定
2013/09/23 职场文书
大学生团日活动总结
2015/05/06 职场文书
flex弹性布局详解
2022/03/20 HTML / CSS
redis protocol通信协议及使用详解
2022/07/15 Redis