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 bind事件使用详解
May 05 Javascript
自写的jQuery异步加载数据添加事件
May 15 Javascript
JavaScript面对国际化编程时的一些建议
Jun 24 Javascript
详解JavaScript中的事件流和事件处理程序
May 20 Javascript
深入理解Angular2 模板语法
Aug 07 Javascript
详解使用grunt完成requirejs的合并压缩和js文件的版本控制
Mar 02 Javascript
Bootstrap fileinput文件上传预览插件使用详解
May 16 Javascript
Vue resource中的GET与POST请求的实例代码
Jul 21 Javascript
vue iview实现动态路由和权限验证功能
Apr 17 Javascript
详解ES6 Promise的生命周期和创建
Aug 18 Javascript
jquery中attr、prop、data区别与用法分析
Sep 25 jQuery
vue项目实现图片上传功能
Dec 23 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 array_slice 取出数组中的一段序列实例
2016/11/04 PHP
php+resumablejs实现的分块上传 断点续传功能示例
2017/04/18 PHP
JQuery自适应IFrame高度(支持嵌套 兼容IE,ff,safafi,chrome)
2011/03/28 Javascript
浅析jquery的js图表组件highcharts
2014/03/06 Javascript
JS动态增加删除UL节点LI及相关内容示例
2014/05/21 Javascript
JS基于构造函数实现的菜单滑动显隐效果【测试可用】
2016/06/21 Javascript
jquery操作ID带有变量的节点实例
2016/12/07 Javascript
AngualrJs清除定时器遇到的坑
2017/10/13 Javascript
JS设计模式之访问者模式定义与用法分析
2018/02/05 Javascript
在element-ui的select下拉框加上滚动加载
2019/04/18 Javascript
vue实现的请求服务器端API接口示例
2019/05/25 Javascript
基于JS实现数字动态变化显示效果附源码
2019/07/18 Javascript
微信小程序中插入激励视频广告并获取收益(实例代码)
2019/12/06 Javascript
vue双击事件2.0事件监听(点击-双击-鼠标事件)和事件修饰符操作
2020/07/27 Javascript
[01:23]一分钟告诉你 DOTA2为什么叫信仰2
2014/06/20 DOTA
python文件的md5加密方法
2016/04/06 Python
详解Python里使用正则表达式的ASCII模式
2017/11/02 Python
Django外键(ForeignKey)操作以及related_name的作用详解
2019/07/29 Python
Django用户认证系统 Web请求中的认证解析
2019/08/02 Python
Python3 socket即时通讯脚本实现代码实例(threading多线程)
2020/06/01 Python
详解基于Scrapy的IP代理池搭建
2020/09/29 Python
python 牛顿法实现逻辑回归(Logistic Regression)
2020/10/15 Python
英国Zoro工具:手动工具,电动工具和个人防护用品
2016/11/02 全球购物
Ted Baker英国官网:男士和女士服装及配件
2017/03/13 全球购物
Brasty波兰:香水、化妆品、手表网上商店
2019/04/15 全球购物
澳大利亚100%丝绸多彩度假装商店:TheSwankStore
2019/09/04 全球购物
大四毕业生学习总结的自我评价
2013/10/31 职场文书
仓库门卫岗位职责
2013/12/22 职场文书
住房公积金接收函
2014/01/09 职场文书
化学教学随笔感言
2014/02/19 职场文书
单位法定代表人授权委托书
2014/09/20 职场文书
领导班子四风查摆对照检查材料思想汇报
2014/10/05 职场文书
新生入学欢迎词
2015/01/26 职场文书
2016高考冲刺决心书
2015/09/23 职场文书
《学会看病》教学反思
2016/02/17 职场文书
Python Matplotlib绘制等高线图与渐变色扇形图
2022/04/14 Python