原來(lái)JS還可以這樣拆箱轉(zhuǎn)換詳解
前言
在讀 Winter 大佬的《重學(xué)前端》欄目時(shí),重溫了 JS 的「拆箱轉(zhuǎn)換」?!秆b箱轉(zhuǎn)換」與「拆箱轉(zhuǎn)換」以前都是了解的,今天來(lái)看,自己所謂的了解也真是一知半解。在閱讀 Winter 老師寫的內(nèi)容后,對(duì)「拆箱轉(zhuǎn)換」這個(gè)知識(shí)點(diǎn)還是不甚清楚,因此我再去深入地了解一番,參考資料詳見文末的「參考鏈接」。
被我們忽略的表象
首先,我們來(lái)看一下例子:
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 的執(zhí)行順序并不固定,而是根據(jù)某個(gè)條件來(lái)決定的,那么是根據(jù)什么呢?那就是在拆箱轉(zhuǎn)換時(shí),調(diào)用了對(duì)象的 ToPrimitive 內(nèi)部函數(shù)時(shí),其會(huì)根據(jù)執(zhí)行上下文,自動(dòng)傳入一個(gè)轉(zhuǎn)換類型參數(shù),暫時(shí)給它命名為 hint。
ToPrimitive
在 JavaScript 標(biāo)準(zhǔn)中,規(guī)定了 ToPrimitive 函數(shù),它是對(duì)象類型到基本類型轉(zhuǎn)換的實(shí)現(xiàn)者(即,拆箱轉(zhuǎn)換);但這是一個(gè)內(nèi)部算法,是編程語(yǔ)言在內(nèi)部執(zhí)行時(shí)遵循的一套規(guī)則。
對(duì)象到 String 和 Number 的轉(zhuǎn)換都遵循“先拆箱再轉(zhuǎn)換”的規(guī)則。通過(guò)拆箱轉(zhuǎn)換,把對(duì)象變成基本類型,再?gòu)幕绢愋娃D(zhuǎn)換為對(duì)應(yīng)的 String 或者 Number。
但是對(duì)于不同的操作,拆箱轉(zhuǎn)換的內(nèi)部實(shí)現(xiàn)也有所區(qū)別,正如上面的例子所示。
「拆箱轉(zhuǎn)換」的調(diào)用規(guī)則及順序如下:
- 檢查對(duì)象中是否有用戶顯式定義的 [Symbol.toPrimitive] 方法,如果有,直接調(diào)用;
- 如果沒有,則執(zhí)行原內(nèi)部函數(shù) ToPrimitive,然后判斷傳入的 hint 值,如果其值為 string,順序調(diào)用對(duì)象的 toString 和 valueOf 方法(其中 toString 方法一定會(huì)執(zhí)行,如果其返回一個(gè)基本類型值,則返回、終止運(yùn)算,否則繼續(xù)調(diào)用 valueOf 方法);
- 如果判斷傳入的 hint 值不為 string,則就可能為 number 或者 default 了,均會(huì)順序調(diào)用對(duì)象的 valueOf 和 toString 方法(其中 valueOf 方法一定會(huì)執(zhí)行,如果其返回一個(gè)基本類型值,則返回、終止運(yùn)算,否則繼續(xù)調(diào)用 toString 方法);
來(lái)看一下第一種情況:
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
第二、三種情況:
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
那么關(guān)于 hint 可取的三種值,都有什么含義?又什么情況對(duì)應(yīng)什么值?
確定 hint 取值
string
當(dāng)在希望是字符串操作,也即發(fā)生對(duì)象到字符串的轉(zhuǎn)換時(shí),傳入內(nèi)部函數(shù) ToPrimitive 的參數(shù)值即為 string:
// output alert(obj); // using object as a property key anotherObj[obj] = 123;
number
當(dāng)在希望是數(shù)值操作,也即發(fā)生對(duì)象到數(shù)值的轉(zhuǎn)換時(shí),傳入內(nèi)部函數(shù) ToPrimitive 的參數(shù)值即為 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
當(dāng)在一些不確定需要將對(duì)象轉(zhuǎn)換成什么基礎(chǔ)類型的場(chǎng)景下,傳入內(nèi)部函數(shù) ToPrimitive 的參數(shù)值即為 default:
// binary plus
let total = car1 + car2;
// obj == string/number/symbol
if (user == 1) { ... };
結(jié)語(yǔ)
如果親愛的讀者們?cè)诒疚闹邪l(fā)現(xiàn)了什么錯(cuò)誤,或者有什么不同的意見,還請(qǐng)留言,一起討論,一起將隱藏的、晦澀的點(diǎn)提出來(lái),然后解決掉。
參考鏈接
- 《重學(xué)前端》——極客時(shí)間APP
- Object to primitive conversion
- ToPrimitive
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- Json對(duì)象與Json字符串互轉(zhuǎn)(4種轉(zhuǎn)換方式)
- js數(shù)組與字符串的相互轉(zhuǎn)換方法
- js 將json字符串轉(zhuǎn)換為json對(duì)象的方法解析
- js中將字符串轉(zhuǎn)換成json的三種方式
- js 字符串轉(zhuǎn)換成數(shù)字的三種方法
- 解析JSON對(duì)象與字符串之間的相互轉(zhuǎn)換
- js字符串轉(zhuǎn)換成數(shù)字與數(shù)字轉(zhuǎn)換成字符串的實(shí)現(xiàn)方法
- JS對(duì)象與JSON格式數(shù)據(jù)相互轉(zhuǎn)換
- js將類數(shù)組對(duì)象轉(zhuǎn)換成數(shù)組對(duì)象
- js實(shí)現(xiàn)數(shù)組轉(zhuǎn)換成json
相關(guān)文章
js實(shí)現(xiàn)瀑布流觸底動(dòng)態(tài)加載數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)瀑布流觸底動(dòng)態(tài)加載數(shù)據(jù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
js實(shí)現(xiàn)canvas圖片與img圖片的相互轉(zhuǎn)換的示例
本篇文章主要介紹了js實(shí)現(xiàn)canvas圖片與img圖片的相互轉(zhuǎn)換的示例,具有一定的參考價(jià)值,有興趣的可以了解一下2017-08-08
javascript實(shí)現(xiàn)根據(jù)函數(shù)名稱字符串動(dòng)態(tài)執(zhí)行函數(shù)的方法示例
這篇文章主要介紹了javascript實(shí)現(xiàn)根據(jù)函數(shù)名稱字符串動(dòng)態(tài)執(zhí)行函數(shù)的方法,結(jié)合實(shí)例形式分析了JS函數(shù)名的判斷及函數(shù)動(dòng)態(tài)調(diào)用相關(guān)操作技巧,需要的朋友可以參考下2016-12-12
JS+CSS實(shí)現(xiàn)自適應(yīng)選項(xiàng)卡寬度的圓角滑動(dòng)門效果
這篇文章主要介紹了JS+CSS實(shí)現(xiàn)自適應(yīng)選項(xiàng)卡寬度的圓角滑動(dòng)門效果,通過(guò)簡(jiǎn)單的css設(shè)置實(shí)現(xiàn)圓角滑動(dòng)門功能,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-09-09
bootstrap 點(diǎn)擊空白處popover彈出框隱藏實(shí)例
下面小編就為大家分享一篇bootstrap 點(diǎn)擊空白處popover彈出框隱藏實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
js根據(jù)給定的日期計(jì)算當(dāng)月有多少天實(shí)現(xiàn)思路及代碼
根據(jù)給定的日期計(jì)算當(dāng)月有多少天,想必這樣的功能大家都想實(shí)現(xiàn)吧,所以本文的出現(xiàn)相當(dāng)有必要,接下來(lái)看下實(shí)現(xiàn)代碼,感興趣的朋友可以了解下,希望對(duì)你有所幫助2013-02-02
JavaScript實(shí)現(xiàn)創(chuàng)建自定義對(duì)象的常用方式總結(jié)
這篇文章主要介紹了JavaScript實(shí)現(xiàn)創(chuàng)建自定義對(duì)象的常用方式,結(jié)合實(shí)例形式總結(jié)分析了JavaScript工廠模式、構(gòu)造函數(shù)模式、原型模式、組合模式等常用的自定義對(duì)象創(chuàng)建模式操作與使用技巧,需要的朋友可以參考下2018-07-07

