• 浅析JavaScript中的装箱和拆箱


      在javascript中有两种数据类型:

      基本类型:字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol

      引用类型:对象(Object)、数组(Array)、函数(Function)

      在 JavaScript 中,有四个基本的包装类型 String、Number、Boolean、Symbol。

    一、装箱操作

      所谓的装箱,是指将基本数据类型转换为对应的引用类型的操作。

      装箱分隐式装箱和显式装箱两种装箱方式。

    1、隐式装箱

      先说「隐式装箱」,隐式装箱是由「引擎自动执行」的。

    let web = 123;

      基本类型是不能添加属性和方法的,添加会报错。

    let web = 'Javascript';
    web.subText = 'JavaScriptSub';
    web.subTextFn = function(){
      console.log('JavascriptSubTextFn');
    };
    console.log(web.subText);//undefined
    console.log(web.subTextFn());//Uncaught TypeError: web.subTextFn is not a function

      那为什么普通字符串类型可以调用方法呢,比如str.substring()、str.indexOf()等,我们接着往下看:

    2、那装箱都做了什么?

      在读取值的时候,引擎会创建一个基本类型所对应的「包装类型的对象」,见下图。

      对于隐式装箱的执行步骤,我们看下面的代码:

    var s1 = 'call_me_R'; // 隐式装箱
    var s2 = s1.substring(2);

      上面代码的执行步骤其实是这样的:

    (1)先创建String类型的一个实例;

    (2)在实例中调用制定的方法;

    (3)销毁这个实例。

      上面的三个步骤转换为代码,如下:

    // 1
    var s1 = new String('call_me_R');
    // 2
    var s2 = s1.substring(2);
    // 3
    s1 = null;

      所以,我们在基本类型值上可以使用方法(比如string的substring等),是因为有「隐式装箱」操作。

      隐式装箱当读取一个基本类型值时,后台会创建一个该基本类型所对应的基本包装类型对象。在这个基本类型的对象上调用方法,其实就是在这个基本类型对象上调用方法。这个基本包装类型的对象是临时的,它只存在于方法调用那一行代码执行的瞬间,执行方法后立即被销毁。这也是在基本类型上添加属性和方法会不识别或报错的原因了。

    3、显式装箱

      装箱的另一种方式是显式装箱,这个就比较好理解了,这是通过基本包装类型对象对基本类型进行显式装箱,如下:

    var name = new String('call_me_R');

      显式装箱的操纵可以对new出来的对象进行属性和方法的添加啦,因为通过new操作符创建的引用类型的实例,在执行流离开当前作用域之前一直保留在内存中

    var objStr = new String('call_me_R');
    objStr.job = 'frontend engineer';
    objStr.sayHi = function(){
        console.log('hello kitty');
    }
    console.log(objStr.job); // frontend engineer
    objStr.sayHi(); // hello kitty

      显式装箱可以添加属性和方法的,隐式装箱是不能添加属性和方法的。

    二、箱操作

      拆箱就和装箱相反了,拆箱是指把引用类型转换成基本的数据类型。通常通过引用类型的valueOf()和toString()方法来实现。

      引用类型的值转成基本类型的值就是拆箱。拆箱必须要提两个方法 toString() 和 valueOf() ,toString() 返回字符串,valueOf() 返回对象本身。

    1、在下面的代码中,留意下valueOf()和toString()返回值的区别:

    var objNum = new Number(64);
    var objStr = new String('64');
    console.log(typeof objNum); // object
    console.log(typeof objStr); // object
    // 拆箱
    console.log(typeof objNum.valueOf()); // 64  number 基本的数字类型,想要的
    console.log(typeof objNum.toString()); // '64'  string 基本的字符类型,不想要的
    console.log(typeof objStr.valueOf()); // '64'   string 基本的数据类型,不想要的
    console.log(typeof objStr.toString()); // '64'  string 基本的数据类型,想要的

    2、更改对象的 toString() 和 valueOf() 两个方法:

    //更改对象的 toString() 和 valueOf() 两个方法:
    var web = {
      'name':'html',
      valueOf: () => {
        console.log("valueOf");
      },
      toString: () => {
        console.log("toString");
      }
    }
    console.log(String(web))//toString undefined
    console.log(Number(web))//valueOf NaN
    var ss = {'web': 22}
    String(ss)
    //"[object Object]"
    ss.toString()
    //"[object Object]"
    ss.valueOf()
    //{web: 22}
    Number(ss)
    //NaN

      执行的逻辑是什么?为什么有时候先走 valueOf() ?为什么有时候先执行 toString()?

      对象中有 toPrimitive 方法,此方法提供了用于将对象强制转换为基元并替换 toString() 和 valueOf() 方法的通用接口。

      运行方法时,判断 PreferredType 的值是哪种类型:

      如果是 Number:

    (1)如果是基本类型,按原样返回。

    (2)否则,输入是一个对象,调用 obj.valueOf() 方法,如果结果是原始的,则将其返回。

    (3)否则,调用 obj.toString() 方法,如果结果是原始数据,则将其返回。

    (4)否则,抛出 TypeError

      如果为 String:那需要交换 2 和3 的执行顺序。

      如果没有 PreferredType ,对于 Date 的实例将其设置为 String。

      对于所有的其他值,设置为 Number。

     参考资料:

    https://juejin.cn/post/6844903859765133320

    https://mp.weixin.qq.com/s/QDHJBCP9E8GyKPlMOExwAA

  • 相关阅读:
    eclipse中设置自动生成的author,date等注释
    JSP基本指令
    java代码注释规范
    java中的 FileWriter类 和 FileReader类的一些基本用法
    关于java中BufferedReader的read()及readLine()方法的使用心得
    java开发中经典的三大框架SSH
    Java访问修饰符(访问控制符)
    Linux环境变量具体内容介绍
    MSG结构体和WndProc窗口过程详解
    Java当出现未被捕获的异常应该如何处理
  • 原文地址:https://www.cnblogs.com/goloving/p/14442541.html
Copyright © 2020-2023  润新知