在讀 Winter 大佬的《重學前端》欄目時,重溫了 JS 的「拆箱轉換」。「裝箱轉換」與「拆箱轉換」之前都是瞭解的,今天來看,本身所謂的瞭解也真是隻知其一;不知其二。在閱讀 Winter 老師寫的內容後,對「拆箱轉換」這個知識點仍是不甚清楚,所以我再去深刻地瞭解一番,參考資料詳見文末的「參考連接」。javascript
首先,咱們來看一下例子:前端
const a = {
name: 'a',
toString () {
console.log(this);
console.log('toString');
return { name: 'toString' };
},
valueOf () {
console.log(this);
console.log('valueOf');
return { name: 'valueOf' };
}
};
a * 2;
// {name: "a", toString: ƒ, valueOf: ƒ}
// valueOf
// {name: "a", toString: ƒ, valueOf: ƒ}
// toString
// Uncaught TypeError: Cannot convert object to primitive value
a + "";
// {name: "a", toString: ƒ, valueOf: ƒ}
// valueOf
// {name: "a", toString: ƒ, valueOf: ƒ}
// toString
// Uncaught TypeError: Cannot convert object to primitive
alert(a);
// {name: "a", toString: ƒ, valueOf: ƒ}
// toString
// {name: "a", toString: ƒ, valueOf: ƒ}
// valueOf
// Uncaught TypeError: Cannot convert object to primitive value
複製代碼
能夠看到,toString
和 valueOf
的執行順序並不固定,而是根據某個條件來決定的,那麼是根據什麼呢?那就是在拆箱轉換時,調用了對象的 ToPrimitive
內部函數時,其會根據執行上下文,自動傳入一個轉換類型參數,暫時給它命名爲 hint
。java
在 JavaScript 標準中,規定了 ToPrimitive
函數,它是對象類型到基本類型轉換的實現者(即,拆箱轉換);但這是一個內部算法,是編程語言在內部執行時遵循的一套規則。git
對象到 String 和 Number 的轉換都遵循「先拆箱再轉換」的規則。經過拆箱轉換,把對象變成基本類型,再從基本類型轉換爲對應的 String 或者 Number。github
可是對於不一樣的操做,拆箱轉換的內部實現也有所區別,正如上面的例子所示。算法
「拆箱轉換」的調用規則及順序以下:編程
[Symbol.toPrimitive]
方法,若是有,直接調用;ToPrimitive
,而後判斷傳入的 hint
值,若是其值爲 string
,順序調用對象的 toString
和 valueOf
方法(其中 toString
方法必定會執行,若是其返回一個基本類型值,則返回、終止運算,不然繼續調用 valueOf
方法);hint
值不爲 string
,則就可能爲 number
或者 default
了,均會順序調用對象的 valueOf
和 toString
方法(其中 valueOf
方法必定會執行,若是其返回一個基本類型值,則返回、終止運算,不然繼續調用 toString
方法);來看一下第一種狀況:微信
const b = {
[Symbol.toPrimitive] (hint) {
console.log(`hint: ${hint}`);
return {};
},
toString () {
console.log('toString');
return 1;
},
valueOf () {
console.log('valueOf');
return 2;
}
};
alert(b); // hint: string
b + ''; // hint: default
b + 500; // hint: default
+b; // hint: number
b * 1; // hint: number
複製代碼
第2、三種狀況:less
const c = {
toString () {
console.log('toString');
return 1;
},
valueOf () {
console.log('valueOf');
return 2;
}
};
alert(c); // 打印出 toString 並 alert 出 1
c + ''; // 前後打印出 valueOf,"2"
c + 500; // 前後打印出 valueOf,502
+c; // 前後打印出 valueOf,2
c * 1; // 前後打印出 valueOf,2
複製代碼
那麼關於 hint
可取的三種值,都有什麼含義?又什麼狀況對應什麼值?編程語言
hint
取值string
當在但願是字符串操做,也即發生對象到字符串的轉換時,傳入內部函數 ToPrimitive 的參數值即爲 string
:
// output
alert(obj);
// using object as a property key
anotherObj[obj] = 123;
複製代碼
number
當在但願是數值操做,也即發生對象到數值的轉換時,傳入內部函數 ToPrimitive 的參數值即爲 number
:
// explicit conversion
let num = Number(obj);
// maths (except binary plus)
let n = +obj; // unary plus
let delta = date1 - date2;
// less/greater comparison
let greater = user1 > user2;
複製代碼
default
當在一些不肯定須要將對象轉換成什麼基礎類型的場景下,傳入內部函數 ToPrimitive 的參數值即爲 default
:
// binary plus
let total = car1 + car2;
// obj == string/number/symbol
if (user == 1) { ... };
複製代碼
若是親愛的讀者們在本文中發現了什麼錯誤,或者有什麼不一樣的意見,還請留言,一塊兒討論,一塊兒將隱藏的、晦澀的點提出來,而後解決掉。
以爲本文不錯的話,分享一下給小夥伴吧~