關於 JS 型別轉換
JS 有六種基本資料型別:
number
string
boolean
undefined
null
symbol
(ES6
新加入)
以及一種引用型別:
object
當這些不同型別的資料之間,需要通過邏輯操作符進行判斷,或者進行運算操作時,就會觸發 JS 的隱性型別轉換機制,對不同型別的資料先進行轉換操作,再執行相關邏輯。
型別轉換規則
JS 種的型別轉換,只有如下三種情況:
- 轉為布林值
- 轉為數字
- 轉為字串
以下是各種資料型別之間相互轉換的表格:
原始值型別 | 目標值型別 | 結果 |
---|---|---|
boolean | 布林值 | 本身值,false 就為 false ,true 就為 true |
number | 布林值 | 0 和 NaN 為 false 否則都為 true |
string | 布林值 | 除了空字串為 false 其他都為 true |
undefined、null | 布林值 | false |
symbol | 布林值 | true |
物件 | 布林值 | true |
陣列 | 布林值 | true |
原始值型別 | 目標值型別 | 結果 |
---|---|---|
boolean | 字串 | true: 'true';false: 'false' |
number | 字串 | 數字字串 |
string | 字串 | 字串本身值 |
undefined、null | 字串 | 拋錯 |
symbol | 字串 | symbol 字串 |
物件 | 字串 | '[object Object]' |
陣列 | 字串 | 空陣列轉為空字串,否則轉為由逗號拼接每一項的字串 |
原始值型別 | 目標值型別 | 結果 |
---|---|---|
boolean | 數字 | true 轉換為 1,false 轉換為 0 |
number | 數字 | 數字本身 |
string | 數字 | 除了都是數字組成的字串,能轉換成數字外,其他都是 NaN |
null | 數字 | 0 |
undefined | 數字 | NaN |
symbol | 數字 | 拋錯 |
物件 | 數字 | NaN |
陣列 | 數字 | 空陣列轉換為0;只有一項(數字)的陣列轉換為這個數字;只有一項(空字串、undefined、null)的陣列轉換為0;除上述以外情況的陣列轉換為 NaN |
觸發 JS 隱式轉換的先決條件
在下面兩種情況下,將會觸發 JS 的隱性型別轉換機制。
- 當使用
==
、&&
、||
等邏輯操作符進行判斷時 - 當使用
+ - * /
四則運算子進行操作時
下面就 ==
和四則運算兩種情況,來分析一下內部的轉化機制:
1. 使用 ==
操作符進行判斷時
先來看下在使用 ==
進行判斷時,隱式轉換的內部機制,判斷步驟如下:
兩個運算元型別一樣的情況:
- 如果兩個運算元是同類基本型別值,則直接比較
- 如果兩個運算元是同類引用型別值,則比較記憶體地址
兩個運算元型別不一樣的情況:
- 如果有一個運算元是布林值,則將這個布林值轉換為數字再進行比較。
- 如果有一個運算元是字串,另一個運算元是數字,則將字串轉換成數字再進行比較
- 如果有一個運算元是引用型別的值,則呼叫該例項的
valueOf
方法,如果得到的值不是基本型別的值,再呼叫該例項的toString
方法,用得到的基本型別的值按照前面的規則進行匹配對比。
以上邏輯轉換成流程圖:
特殊情況:
null == undefined
判斷為true
null
和undefined
無法轉換為基本型別值NaN != NaN
判斷為true
,事實上,NaN
更像一個特例,誰都不等於
2. 使用 +
進行判斷時
- 兩個運算元都為數字時直接執行加法操作
- 其他情況下,將兩個運算元都轉換成字串,進行字串拼接操作。
3. 使用除 +
號以外的四則運算子判斷時
直接進行數學運算,行就行,不行就直接 NaN
,簡單粗暴。
型別轉換的經典面試題目
[] == ![]
輸出結果是?{} == !{}
輸出結果是?1 + '1'
輸出結果是?true + true
輸出結果是?4 + []
輸出結果是?4 + {}
輸出結果是?4 + [1]
輸出結果是?4 + [1, 2, 3, 4]
輸出結果是?'a' + + 'b'
輸出結果是?
第一題的轉化邏輯如下:
// 嘗試判斷,!運算子的優先順序大於 ==,所以實際上這裡還涉及到!的運算。
[] == ![]
// 將右邊 ![] 進行轉換
[] == false
// 隱式轉換布林值為數字
[] == 0
// 轉換左邊的 [],呼叫 [] 例項的 valueOf 方法
[] == 0
// valueOf 方法返回的不是基本型別值,再次呼叫 toString 方法
'' == 0
// 隱式轉換字串為數字
0 == 0
// 返回結果
true
複製程式碼
第二題的轉化邏輯如下:
// 嘗試判斷,!運算子的優先順序大於 ==,所以實際上這裡還涉及到!的運算。
{} == !{}
// 將右邊 !{} 進行轉換
{} == false
// 隱式轉換布林值為數字
{} == 0
// 轉換左邊的 {},呼叫 {} 例項的 valueOf 方法
{} == 0
// valueOf 方法返回的不是基本型別值,再次呼叫 toString 方法
'[object Object]' == 0
// 隱式轉換字串為數字
1 == 0
// 返回結果
false
複製程式碼
後面的題目:
// 第三題
1 + '1' == '1' + '1' == '11'
// 第四題
true + true == 1 + 1 == 2
// 第五題
4 + [] == '4' + '' == '4'
// 第六題
4 + {} == '4' + '[object Object]' == '4[object Object]'
// 第七題
4 + [1] == '4' + '1' == '41'
// 第八題
4 + [1, 2, 3, 4] == '4' + '1, 2, 3, 4' == '41,2,3,4'
// 第九題,稍微有點複雜,+'b'是被轉換成了 NaN
'a' + + 'b' == 'a' + 'NaN' == 'aNaN'
複製程式碼
本文參考了一些別人的觀點,再加上自己手動控制檯列印認證,如果有錯誤,歡迎指出,我即時修改。