本文首發於個人部落格
看到這個是不是有一種想打人的感覺,垃圾 JavaScript,這特麼都什麼鬼,相信很多人不管是筆試還是面試,都被 JS 的型別轉換難道過,相信認真看完我這篇文章,媽媽再也不用擔心型別轉換的問題了。
原始值到原始值的轉換
-
原始值轉化為布林值
所有的假值(undefined、null、0、-0、NaN、””)會被轉化為 false,其他都會被轉為 true
-
原始值轉化為字串 都相當於 原始值 + ""
-
原始值轉為數字
- 布林轉數字:true -> 1, false -> 0
- 字串轉數字:以數字表示的字串可以直接會轉為字串,如果字串頭尾有空格會忽略,但是空格在中間,轉換結果就是 NaN。
+" 66" // 66 +" 6 7 " // NaN 複製程式碼
原始值到物件的轉換
- null 和 undefined 轉物件直接拋異常
- 原始值通過呼叫 String()、Number()、Boolean()建構函式,轉換為他們各自的包裝物件
物件到原始值的轉換
- 物件轉為布林都為 true
- 物件到字串
- 如果物件有 toString() 方法,就呼叫 toString() 方法。如果該方法返回原始值,就講這個值轉化為字串。
- 如果物件沒有 toString() 方法或者 該方法返回的不是原始值,就會呼叫該物件的 valueOf() 方法。如果存在就呼叫這個方法,如果返回值是原始值,就轉化為字串。
- 否則就報錯
- 物件到數字
- 物件轉化為數字做了跟物件轉化為字串做了想同的事兒,不同的是後者是先呼叫 valueOf 方法,如果呼叫失敗或者返回不是原始值,就呼叫 toString 方法。
- 補充。一些常用內建物件 toString 方法和 valueOf 的轉換規則
- toString 相關
- valueOf 相關
== 運算子如何進行型別轉換
- 如果一個值是null,另一個值是undefined,則相等
- 如果一個是字串,另一個值是數字,則把字串轉換成數字,進行比較
- 如果任意值是true,則把true轉換成1再進行比較;如果任意值是false,則把false轉換成0再進行比較
- 如果一個是物件,另一個是數值或字串,把物件轉換成基礎型別的值再比較。物件轉換成基礎型別,利用它的 toString 或者 valueOf 方法。 js 核心內建類,會嘗試 valueOf 先於 toString(可以理解為物件優先轉換成數字);例外的是 Date,Date 利用的是 toString 轉換。非 js 核心的物件,通過自己的實現中定義的方法轉換成原始值。
+ 運算子如何進行型別轉化
-
如果作為一元運算子就是轉化為數字,常常用來將字串轉化為數字
+"2" // 2 2+false // 0 複製程式碼
-
如果作為二元運算子就有兩種轉換方式
- 兩邊如果有字串,另一邊一會轉化為字串進行相加
- 如果沒有字串,兩邊都會轉化為數字進行相加,物件也根據前面的方法轉化為原始值數字。
- 如果其中的一個運算元是物件,則將物件轉換成原始值,日期物件會通過 toString() 方法進行轉換,其他物件通過 valueOf()方法進行轉換,但是大多數方法都是不具備可用的 valueOf() 方法,所以還是會通過 toString() 方法執行轉換。
流程圖如下:
實戰分析
1. []+[] // ""
_1. 首先運算子是 + 運算子而且很明顯是二元運算子,並且有物件,所以選擇最後一點,運算元是物件,將物件轉換為原始值。
_2. 兩邊物件都是陣列,左邊的陣列先呼叫 valueOf() 方法無果,然後去呼叫 toString(), 方法,在 toString() 的轉化規則裡面有『將陣列轉化為字串,用逗號分隔』,由於沒有其他元素,所以直接是空字串 “”。
_3. 因為加號有一邊是字串了,所以另外一邊也轉為 字串,所以兩邊都是空字串 “”。
_4. 所以加起來也是空字串 “”。
2. (! + [] + [] + ![]).length // 9
_1. 首先我們會看到挺多一元運算子,「+」、「!」,對於一元運算子是右結合性,所以可以畫出以下運算順序。
_2. 對於+[]
,陣列是會被轉化為數字的而不是字串,可見「+ 運算子如何進行型別轉化」的第一條,所以經過第一步就會轉化為
(!0 + [] + false).length
_3. 第二步比較簡單,0 轉化為布林值就是 false,所以經過第二步就轉化為
(true + [] + false).length
_4. 第三步中間的 []
會轉為空字串,在「+ 運算子如何進行型別轉化」第二條的第三點,物件會被轉轉化為原始值,就是空字元,所以經過第三步之後就會變成
("true" + false).length
_5. 第五步就比較簡單啦,最終就是
"truefalse".length // 9