前言#
由於眾多歷史遺留原因,JavaScript(js)對於類型的掌控沒有那麼強(這也就促成了 TypeScript 的誕生),在日常的開發和刷題時,常常會被 js 的一些「隱式轉換」給折磨得不成人樣,即使是老 js 人有時候都會犯一些錯誤。本文將直接涵蓋 js 的所有隱式轉換情況,讓你一篇文章就能搞定 JavaScript 的隱式轉換。
一張圖查看 js 地獄般的隱式轉換:
1. 減、乘、除#
⭐️當我們對各種非「Number」類型應用數學運算符(- * /
)時,會先將非「Number」類型轉換為「Number」類型。
1 - true // 0,首先將 true 轉換為數字 1,然後執行 1 - 1
1 - null // 1,首先將 null 轉換為數字 0,然後執行 1 - 0
1 * undefined // NaN,undefined 轉換為數字是 NaN
2 * ['5'] // 10,['5']首先會變成 '5',然後再變成數字 5
上面例子中的 ['5'] 的轉換,涉及到拆箱操作,將來有機會再出一篇文章說明。
2. 加法的特殊性#
⭐️為什麼加法要區別對待?因為 JavaScript 中的 +
還可以用來拼接字符串。請記住以下 3 條規則:
- 當一側為「String」類型時,被識別為字符串拼接,並且會優先將另一側轉換為字符串類型。
- 當一側為「Number」類型,另一側為原始類型時,將原始類型轉換為「Number」類型。
- 當一側為「Number」類型,另一側為引用類型時,將引用類型和「Number」類型轉換成字符串後拼接。
⭐️以上 3 點,優先級從高到低,即 3+'abc'
會應用規則 1,而 3+true
會應用規則 2。
123 + '123' // 123123(規則1)
123 + null // 123(規則2)
123 + true // 124(規則2)
123 + {} // 123[object Object](規則3)
邏輯語句中的類型轉換#
當我們使用 if
、while
、for
等語句時,我們期望表達式是一個「Boolean」值,所以一定伴隨著隱式類型轉換。而這裡面又分為兩種情況:
1. 單個變量#
⭐️如果只有單個變量,會先將變量轉換為布林值。
我們可以參考附錄的轉換表來判斷各種類型轉變為「Boolean」後的值。
不過這裡有個小技巧:
只有「null」、「undefined」、「''」、「NaN」、「0」、「false」這幾個是「false」,其他的情況都是「true」,比如「{}」、「[]」。
2. 使用 == 比較中的 5 條規則#
雖然我們可以嚴格使用 ===
,但了解 ==
的特性還是很有必要的。
⭐️根據 ==
兩側的數據類型,我們總結出 5 條規則:
- 規則 1:「NaN」和其他任何類型比較永遠返回「false」(包括和它自己)。
NaN == NaN // false
- 規則 2:布林值和其他任何類型比較時,布林值首先被轉換為數字類型。
true == 1 // true
true == '2' // false,先將 true 變成 1,而不是將 '2' 變成 true
true == ['1'] // true,先將 true 變成 1,['1']拆箱成 '1',再參考規則3
true == ['2'] // false,同上
undefined == false // false,首先 false 變成 0,然後參考規則4
null == false // false,同上
- 規則 3:「String」和「Number」比較時,先將「String」轉換為「Number」類型。
123 == '123' // true,'123' 會先變成 123
'' == 0 // true,'' 會首先變成 0
規則 4:「null == undefined」比較結果是「true」,除此之外,「null」、「undefined」和其他任何結果的比較值都為「false」。
null == undefined // true
null == '' // false
null == 0 // false
null == false // false
undefined == '' // false
undefined == 0 // false
undefined == false // false
規則 5:「原始類型」和「引用類型」做比較時,引用類型會依照「ToPrimitive」規則轉換為原始類型。
⭐️「ToPrimitive」規則是引用類型向原始類型轉變的規則,它遵循先「valueOf」後「toString」的模式,期望得到一個原始類型。
如果仍然無法得到一個原始類型,就會拋出 TypeError
。
'[object Object]' == {}
// true,對象和字符串比較,對象通過 toString 得到一個基本類型值
'1,2,3' == [1, 2, 3]
// true,同上,[1, 2, 3]通過 toString 得到一個基本類型值
通過幾個特別的題目來練習一下吧!
1. [] == ![]
- 第一步,![] 會變成 false
- 第二步,應用規則2,題目變成:[] == 0
- 第三步,應用規則5,[]的valueOf是0,題目變成:0 == 0
- 所以,答案是 true!
2. [undefined] == false
#
- 第一步,應用規則5,[undefined]通過toString變成'',
題目變成 '' == false
- 第二步,應用規則2,題目變成 '' == 0
- 第三步,應用規則3,題目變成 0 == 0
- 所以,答案是 true!
// 但是 if([undefined]) 又是個true!
3. 更多的題目#
更多的練習,大家去生活中去發現吧。(悲慘的生活)
⭐️強烈建議大家去找各種奇奇怪怪的題目,反復練習上面 5 條規則,直到熟練於心。
附錄 1:類型轉換表#
這個表格非常實用,在執行上面提到的轉換規則時,可以參考這個對照表。