• 一眼毁三观:JS中令人发指的valueOf方法


    剧透:文章末尾有两个小问题待解答,路过的兄弟请百忙之中抽空看下~~~

    彭老湿近期月报里提到了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的内部转换规则比想的要略复杂些,此处不展开。

    啰啰嗦嗦说了一大通,现在还有两个问题存在疑惑:

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

    最后的最后:

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

  • 相关阅读:
    Android TabHost(选项卡)
    监控工具之---Prometheus查询持久性(六)
    监控工具之---Prometheus表达式promQL生产中应用(五)
    Grafana Configuration 参数详解(1)
    监控工具之---Prometheus数据可视化Grafana(七)
    监控工具之---Prometheus 安装详解(三)
    监控工具之---Prometheus 配置exporter四)
    Kubernetes容器编排技术---kubectl命令行工具用法详解(三)
    Kubernetes容器编排技术---Kubernetes基于kubeadm安装与配置(二)
    Azure Iaas基础之---创建虚拟机
  • 原文地址:https://www.cnblogs.com/chyingp/p/valueOf.html
Copyright © 2020-2023  润新知