[基礎] JavaScript 型別轉換及面試題

不寫bug的米公子發表於2019-01-15

關於 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. 當使用 ==&&|| 等邏輯操作符進行判斷時
  2. 當使用 + - * / 四則運算子進行操作時

下面就 == 和四則運算兩種情況,來分析一下內部的轉化機制:



1. 使用 == 操作符進行判斷時

先來看下在使用 == 進行判斷時,隱式轉換的內部機制,判斷步驟如下:

兩個運算元型別一樣的情況:

  1. 如果兩個運算元是同類基本型別值,則直接比較
  2. 如果兩個運算元是同類引用型別值,則比較記憶體地址
兩個運算元型別不一樣的情況:
  1. 如果有一個運算元是布林值,則將這個布林值轉換為數字再進行比較。
  2. 如果有一個運算元是字串,另一個運算元是數字,則將字串轉換成數字再進行比較
  3. 如果有一個運算元是引用型別的值,則呼叫該例項的 valueOf 方法,如果得到的值不是基本型別的值,再呼叫該例項的 toString 方法,用得到的基本型別的值按照前面的規則進行匹配對比。

以上邏輯轉換成流程圖:

[基礎] JavaScript 型別轉換及面試題

特殊情況:
  1. null == undefined 判斷為 true
  2. nullundefined 無法轉換為基本型別值
  3. NaN != NaN 判斷為 true,事實上,NaN 更像一個特例,誰都不等於

2. 使用 + 進行判斷時

  1. 兩個運算元都為數字時直接執行加法操作
  2. 其他情況下,將兩個運算元都轉換成字串,進行字串拼接操作。

3. 使用除 + 號以外的四則運算子判斷時

直接進行數學運算,行就行,不行就直接 NaN,簡單粗暴。


型別轉換的經典面試題目

  1. [] == ![] 輸出結果是?
  2. {} == !{} 輸出結果是?
  3. 1 + '1' 輸出結果是?
  4. true + true 輸出結果是?
  5. 4 + [] 輸出結果是?
  6. 4 + {} 輸出結果是?
  7. 4 + [1] 輸出結果是?
  8. 4 + [1, 2, 3, 4] 輸出結果是?
  9. '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'
複製程式碼

本文參考了一些別人的觀點,再加上自己手動控制檯列印認證,如果有錯誤,歡迎指出,我即時修改。

相關文章