在學(xué)習(xí)《關(guān)于類型,有哪些你不知道的細(xì)節(jié)》一章節(jié)中非驮,講到了javascript
內(nèi)置了Symbol.toPrimitive
屬性,可自定義類型轉(zhuǎn)換操作必怜。
typeof
我們最常使用typeof
來進(jìn)行類型檢測(cè)养涮,對(duì)于基本類型使用typeof
能得到我們想要的結(jié)果
console.log(typeof '123') //'string'
console.log(typeof 123) //'number'
console.log(typeof undefined) //'undefined'
console.log(typeof true) //'boolean'
console.log(typeof Symbol('foo')) //'symbol'
對(duì)于復(fù)雜類型使用typeof
進(jìn)行判斷,就不是我們想要的結(jié)果了罐监。
console.log(typeof {a: 1}) //'object'
console.log(typeof new Date()) //'object'
console.log(typeof [1,3,4]) //'object'
console.log(typeof new String('123')) //'object'
console.log(typeof new RegExp()) //'object'
顯然我們對(duì)new Date()
進(jìn)行類型判斷時(shí)吴藻,想要得到是Date
;對(duì)數(shù)組進(jìn)行類型判斷時(shí)弓柱,想要得到Array
沟堡,但是用typeof
進(jìn)行判斷時(shí),得到的結(jié)果都是object
矢空,所以對(duì)復(fù)雜類型使用typeof
結(jié)果都是object
航罗。
這里有兩個(gè)特殊的值,對(duì)他們使用typeof
進(jìn)行類型檢測(cè)屁药,和你想象的結(jié)果會(huì)不一樣
console.log(typeof null) //'object'
console.log(typeof function fn(){}) //'function'
雖然null
是基本類型粥血,使用typeof
進(jìn)行類型檢測(cè)時(shí),結(jié)果卻是object
酿箭;而function
是復(fù)雜類型复亏,使用typeof
進(jìn)行類型檢測(cè)卻是function
。
當(dāng)你類型不確定時(shí)缭嫡,要謹(jǐn)慎使用typeof
進(jìn)行類型檢測(cè)缔御。
toString
使用typeof
無法準(zhǔn)確的判斷出想要的類型,這里就可以使用toString
方法進(jìn)行判斷
let type = {}.toString
console.log(type.call('123')) //'[object String]'
console.log(type.call(123)) //'[object Number]'
console.log(type.call(true)) //'[object Boolean]'
console.log(type.call(undefined)) //'[object Undefined]'
console.log(type.call(Symbol('foo'))) //'[object Symbol]'
console.log(type.call(null)) //'[object Null]'
console.log(type.call(function fn() {})) //'[object Function]'
console.log(type.call({a: 11})) //'[object Object]'
console.log(type.call(new Date)) //'[object Date]'
console.log(type.call(new RegExp)) //'[object RegExp]'
console.log(type.call([1,2,3])) //'[object Array]'
使用toString
可以很好的解決了類型判斷的問題妇蛀,從上面例子中可以看出無論是基本類型耕突,還是復(fù)雜類型都能準(zhǔn)確的判斷出來。
這里({}.toString).call(123)
等同于Object.prototype.toString.call(123)
Symbol.toPrimitive
前面講解了如何進(jìn)行類型檢測(cè)评架,在類型檢測(cè)時(shí)眷茁,實(shí)際上是發(fā)生了類型轉(zhuǎn)換,那么類型轉(zhuǎn)換在javascript
內(nèi)部是如何實(shí)現(xiàn)的呢纵诞?
將對(duì)象轉(zhuǎn)換到基本類型時(shí)上祈,javascript
提供了toSring
和valueOf
的轉(zhuǎn)換方法。
let o = {
valueOf: () => {console.log('valueOf'); },
toString: () => {console.log('toString');}
}
String(o) //'toString'
Number(o) //'valueOf'
將對(duì)象轉(zhuǎn)換成string
類型時(shí),會(huì)調(diào)用toString
方法雇逞;將對(duì)象轉(zhuǎn)換成number
時(shí)荤懂,會(huì)調(diào)用valueOf
方法。
如果在調(diào)用toString
時(shí)沒有得到基本類型值時(shí)塘砸,則會(huì)調(diào)用valueOf
节仿,再調(diào)用valueOf
時(shí)也沒有得到基本類型,則會(huì)報(bào)TypeError
錯(cuò)誤
同理在調(diào)用valueOf
時(shí)也是如此掉蔬。
那么為什么在轉(zhuǎn)換成string
時(shí)會(huì)先調(diào)用toString
方法廊宪,而轉(zhuǎn)換成number
時(shí)會(huì)先調(diào)用valueOf
方法呢?
這是因?yàn)?code>javascript內(nèi)置了一個(gè)Symbol.toPrimitive
的屬性女轿。當(dāng)對(duì)象被要被轉(zhuǎn)換為基本類型時(shí)箭启,會(huì)調(diào)用Symbol.toPrimitive
,同時(shí)會(huì)傳入一個(gè)hint
參數(shù):
- 如果想要轉(zhuǎn)換成
string
蛉迹,hint
值為string
傅寡,則會(huì)順序調(diào)用toString
、valueOf
北救,toString
一定會(huì)被執(zhí)行荐操,其值如果返回基本類型時(shí),則return
珍策,終止運(yùn)算托启,否則繼續(xù)調(diào)用valueOf
,如果過調(diào)用valueOf
沒有得到基本類型攘宙,則會(huì)報(bào)TypeError
錯(cuò)誤屯耸; - 如果想要轉(zhuǎn)換成
number
,hint
值為number
蹭劈,則會(huì)順序調(diào)用valueOf
疗绣、toString
,valueOf
一定會(huì)被執(zhí)行链方,其值如果返回基本類型時(shí)持痰,則return
灶搜,終止運(yùn)算祟蚀,否則繼續(xù)調(diào)用toString
方法,如果調(diào)用toString
沒有得到基本類型割卖,則會(huì)報(bào)TypeError
錯(cuò)誤前酿; - 如果不確定是到底要轉(zhuǎn)換成
string
還是number
,hint
值為default
鹏溯,則會(huì)順序調(diào)用valueOf
罢维、toString
,valueOf
一定會(huì)被執(zhí)行丙挽,其值如果返回基本類型時(shí)肺孵,則return
匀借,終止運(yùn)算,否則繼續(xù)調(diào)用toString
方法平窘,如果調(diào)用toString
沒有得到基本類型吓肋,則會(huì)報(bào)TypeError
錯(cuò)誤。
如何用戶顯示指定了Symbol.toPrimitive
方法瑰艘,這會(huì)直接調(diào)用用戶定義的Symbol.toPrimitive
方法:
let o = {
[Symbol.toPrimitive](hint){
console.log(`hint: ${hint}`)
},
valueOf: () => {console.log('valueOf'); }, //未執(zhí)行
toString: () => {console.log('toString');} //未執(zhí)行
}
String(o) //'hint: string'
Number(o) //'hint: number'
o + '' //'hint: default'