前言
在讀 Winter 大佬的《重學前端》欄目時,重溫了 JS 的「拆箱轉換」。「裝箱轉換」與「拆箱轉換」以前都是了解的,今天來看,自己所謂的了解也真是一知半解。在閱讀 Winter 老師寫的內容后,對「拆箱轉換」這個知識點還是不甚清楚,因此我再去深入地了解一番,參考資料詳見文末的「參考鏈接」。
被我們忽略的表象
首先,我們來看一下例子:
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 valuea + "";// {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。
ToPrimitive
在 JavaScript 標準中,規定了 ToPrimitive 函數,它是對象類型到基本類型轉換的實現者(即,拆箱轉換);但這是一個內部算法,是編程語言在內部執行時遵循的一套規則。
對象到 String 和 Number 的轉換都遵循“先拆箱再轉換”的規則。通過拆箱轉換,把對象變成基本類型,再從基本類型轉換為對應的 String 或者 Number。
但是對于不同的操作,拆箱轉換的內部實現也有所區別,正如上面的例子所示。
「拆箱轉換」的調用規則及順序如下:
來看一下第一種情況:
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: defaultb + 500; // hint: default+b; // hint: numberb * 1; // hint: number
第二、三種情況:
const c = { toString () { console.log('toString'); return 1; }, valueOf () { console.log('valueOf'); return 2; }};alert(c); // 打印出 toString 并 alert 出 1c + ''; // 先后打印出 valueOf,"2"c + 500; // 先后打印出 valueOf,502+c; // 先后打印出 valueOf,2c * 1; // 先后打印出 valueOf,2
那么關于 hint 可取的三種值,都有什么含義?又什么情況對應什么值?
確定 hint 取值
string
當在希望是字符串操作,也即發生對象到字符串的轉換時,傳入內部函數 ToPrimitive 的參數值即為 string:
// outputalert(obj);// using object as a property keyanotherObj[obj] = 123;
number
當在希望是數值操作,也即發生對象到數值的轉換時,傳入內部函數 ToPrimitive 的參數值即為 number:
// explicit conversionlet num = Number(obj);// maths (except binary plus)let n = +obj; // unary pluslet delta = date1 - date2;// less/greater comparisonlet greater = user1 > user2;
default
當在一些不確定需要將對象轉換成什么基礎類型的場景下,傳入內部函數 ToPrimitive 的參數值即為 default:
// binary pluslet total = car1 + car2;// obj == string/number/symbolif (user == 1) { ... };
結語
如果親愛的讀者們在本文中發現了什么錯誤,或者有什么不同的意見,還請留言,一起討論,一起將隱藏的、晦澀的點提出來,然后解決掉。
參考鏈接
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。
新聞熱點
疑難解答