淺析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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM