看完ECMAScript5.1中文版的介紹之后,相信很多小伙伴的心情應該是這樣的:
別看上面說的有點花里胡哨的,其實我們可以用很簡單的話來總結出來。由于本篇文章核心是“==”是如何進行類型轉換,我就總結一下類型不同的情況下“==”是如何比較的。
具體流程圖如下:
備注:
Javascript的數(shù)據(jù)類型可以分為以下兩種:
Boolean類型、String類型轉換成Number類型的規(guī)則(ToNumber)
Boolean類型
Boolean | Number |
---|---|
true | 1 |
false | 0 |
String類型
標準的數(shù)字格式
如果是標準的數(shù)字格式,轉換成Number類型相比不用多說,比如下面這幾個栗子🌰:
"123" => 123 "12.34" => 12.34 "0.12" => 0.12 "-12.34" => -12.34
非標準的數(shù)字格式
但是如果是非標準的數(shù)據(jù)格式,要分兩種情況來考慮:
只包含數(shù)字并且最多只有1個點
這種情況下會首先進行補0和去0的操作,下面看幾個栗子🌰:
"01234" => 1234 ".1" => 0.1 "12." => 12 "1.000" => 1 "-02.30" => -2.3
包含非數(shù)字以及含有多個1個點
這種情況下統(tǒng)統(tǒng)返回NaN,意為“Not a Number”,這里我們要注意一下,NaN還是Number類型,下面看幾個栗子🌰:
"123aa4" => NaN "哈嘍,DD" => NaN typeof NaN => "numer"
引用類型轉換成原始數(shù)據(jù)類型的規(guī)則(ToPrimitive)
在介紹轉換規(guī)則之前,首先我們我們介紹一下引用類型都帶有的兩個方法:
這二者都可以將引用類型轉換成原始數(shù)據(jù)類型,接下來我們對二者做一個詳細的介紹:
Object.prototype.toString
MDN是這樣解釋的:
The toString() method returns a string representing the object.(toString()這個方法返回一個代表這個對象的字符串)
舉個栗子🌰:
const obj = {} console.log(String(obj)) //"[object Object]" obj.toString = function(){ return 'Hello,Teacher Cang!' } console.log(String(obj)) //"Hello,Teacher Cang!"
Object.prototype.valueOf
MDN是這樣解釋的:
The valueOf() method returns the primitive value of the specified object.( valueOf()這個方法返回這個對象的原始數(shù)據(jù)值)
舉個栗子🌰:
const obj = {} console.log(Number(obj)) //NaN obj.valueOf = function(){ return 12345; } console.log(Number(obj)) //12345
valueOf和toString的優(yōu)先級
關于這二者的優(yōu)先級,在不同的情況下有著不同的優(yōu)先級,下面我們根據(jù)不同情況介紹一下。
ToNumber
看個栗子🌰:
const obj = { toString(){ console.log('調用了toString'); return 'Hello,Teacher Cang!'; }, valueOf(){ console.log('調用了valueOf'); return 12345; } } console.log(Number(obj)); 控制臺
通過上面的代碼的運行結果,我們得出這么一個結論:
在ToNumber情況下,valueOf的優(yōu)先級大于toString。
接下里我們看這么一種情況,如果valueOf返回的并不是原始數(shù)據(jù)類型會怎么樣。
const obj = { toString(){ console.log('調用了toString'); return 12345; }, valueOf(){ console.log('調用了valueOf'); return {}; } } console.log(Number(obj)); 控制臺
從上面的運行結果中,我們可以得出這么一個結論:
在ToNumber情況下,如果valueOf返回的不是原始數(shù)據(jù)類型,則會自動調用toString。
打破砂鍋問到底,再來一個非常極端的情況,如果說valueOf和toString返回的都不是原始數(shù)據(jù)類型,這時又該怎么樣呢?同樣,我們繼續(xù)看一下運行結果:
const obj = { toString(){ console.log('調用了toString'); return {}; }, valueOf(){ console.log('調用了valueOf'); return {}; } } console.log(Number(obj)); 控制臺
從上面的運行結果中,我們再次可以得出這么一個結論:
在ToNumber情況下,如果valueOf和toString返回的都不是原始數(shù)據(jù)類型,那么js會拋出異常,提示無法將引用類型轉換原始數(shù)據(jù)類型。
根據(jù)三組代碼的運行的結果,我們最后總結一下:
在ToNumber情況下,js會優(yōu)先調用valueOf,如果valueOf返回的不是原始數(shù)據(jù)類型,則會接著調用toString,如果toString返回的也不是原始數(shù)據(jù)類型,js會拋出一個異常,提示無法將引用類型轉換原始數(shù)據(jù)類型。
具體流程圖如下:
ToString
看個栗子🌰:
const obj = { toString(){ console.log('調用了toString'); return 'Hello,Teacher Cang!'; }, valueOf(){ console.log('調用了valueOf'); return 12345; } } console.log(String(obj)); 控制臺
通過上面的代碼的運行結果,我們得出這么一個結論:
在ToString情況下,toString的優(yōu)先級大于valueOf。
同樣我們看一下,toString返回的值不是原始數(shù)據(jù)類型時會怎樣:
const obj = { toString(){ console.log('調用了toString'); return {}; }, valueOf(){ console.log('調用了valueOf'); return 'Hello,Teacher Cang!'; } } console.log(String(obj)); 控制臺
根據(jù)運行結果我們可以得出:
在ToString情況下,如果toString返回的不是原始數(shù)據(jù)類型,則會自動調用valueOf。
最后我們看一下極端情況,二者返回的都不是原始數(shù)據(jù)類型:
const obj = { toString(){ console.log('調用了toString'); return {}; }, valueOf(){ console.log('調用了valueOf'); return {}; } } console.log(String(obj)); 控制臺
我們又發(fā)現(xiàn):
在ToString情況下,如果toString和valueOf返回的都不是原始數(shù)據(jù)類型,那么js會拋出異常,提示無法將引用類型轉換原始數(shù)據(jù)類型。
我們將三個結論綜合一下:
在ToString情況下,js會優(yōu)先調用toString,如果toString返回的不是原始數(shù)據(jù)類型,則會接著調用valueOf,如果valueOf返回的也不是原始數(shù)據(jù)類型,js會拋出一個異常,提示無法將引用類型轉換原始數(shù)據(jù)類型。
具體流程圖如下:
“==”下的valueOf和toString的優(yōu)先級
從文章前面我們總結出來“==”的比較流程來看,引用類型轉換成原始數(shù)據(jù)類型之后,如果是Sting類型的話,還要再次轉成Number類型,因此“==”下的引用類型轉換原始數(shù)據(jù)類型過程中,遵循ToNumber的優(yōu)先級規(guī)則。
const obj = { toString(){ console.log('調用了toString'); return 'Hello,Teacher Cang!'; }, valueOf(){ console.log('調用了valueOf'); return 12345; } } console.log(obj==12345); 控制臺
const obj = { toString(){ console.log('調用了toString'); return 12345; }, valueOf(){ console.log('調用了valueOf'); return {}; } } console.log(obj==12345); 控制臺
const obj = { toString(){ console.log('調用了toString'); return {}; }, valueOf(){ console.log('調用了valueOf'); return {}; } } console.log(obj==12345); 控制臺
“==”之外的類型轉換
“==”號只涉及到了ToPrimitive和ToNumber這兩種轉換,ToBoolean和ToString這兩個沒有涉及到的我們也介紹一下。
ToBoolean
對于ToBoolean,我們只需要記住幾個特例是轉成false的,其余的皆為true。
Boolean('') => false Boolean(undefined) => false Boolean(null) => false Boolean(0) => false
ToString
Number to String
Number轉String之前,首先會做一個去0和補0的操作,然后再去轉成String類型。
String(1.234) => "1.234" String(NaN) => "NaN" String(.1234) => "0.1234" String(1.23400) => "1.234"
Boolean to String
String(true) => "true" String(false) => "false"
null和undefined to String
String(null) => "null" String(undefined) => "undefined"
引用類型 to String
引用類型先ToPrimitive轉換成原始數(shù)據(jù)類型,若轉換后的原始數(shù)據(jù)類型不是String類型,再做String類型的轉換。
const obj = { toString(){ console.log('調用了toString'); return true; } } console.log(String(obj)) 控制臺
總結
“==”下的類型轉換,要分為兩種情況來考慮。第一種,原始數(shù)據(jù)類型;第二種,引用類型。原始數(shù)據(jù)類型中String類型和Boolean類型是需要轉換成Number類型再去比較的,而引用類型則需要先轉換成原始數(shù)據(jù)類型再進行后續(xù)的轉換。搞清整個流程之后,我們再去理解“==”涉及到的ToNumber和ToPrimitive是如何進行轉換的。按照這樣子的理解步驟走,我們對“==”隱藏下的類型轉換會有比較清晰的認識。另外,“==”不涉及到ToString和ToBoolean的類型轉換,在文章的后面部分我也加上去了,希望可以給小伙伴們一個更加全面的類型轉換的認識。最后附上完整的“==”類型轉換的流程圖:
總結
聲明:本網(wǎng)頁內容旨在傳播知識,若有侵權等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com