在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