zoukankan      html  css  js  c++  java
  • 浅析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

  • 相关阅读:
    7.21 高博教育 数组 内存
    【基础扎实】Python操作Excel三模块
    PAT 甲级 1012 The Best Rank
    PAT 甲级 1011  World Cup Betting
    PAT 甲级 1010 Radix
    链式线性表——实验及提升训练
    循环程序设计能力自测
    链表应用能力自测
    PAT 甲级 1009 Product of Polynomials
    1008 Elevator (20分)
  • 原文地址:https://www.cnblogs.com/goloving/p/14442541.html
Copyright © 2011-2022 走看看