很多人包括我在內很牴觸這種問題?,因為很長一段時間我一直弄不明白 == 和 === 到底是怎麼個規則。如果你也沒鬧明白 == 和 ===,讀了這篇文章應該至少不會見到這倆操作符就覺得噁心了吧?。
另外需要注意的是,== 的英文名叫 Abstract Equality Comparison;=== 則是 Strict Equality Comparison。
廢話不多說,我們開始搞起
== 操作符
== 操作符基本規則
首先需要注意的是
- 如果要比較的兩個項是同種型別的,那麼 == 就會返回 === 操作符的執行結果。舉個例子?
2 == 3
最後會返回2 === 3
的執行結果 - 如果要比較的兩個項是不同型別的,== 就會對其中一個或兩者都進行型別轉換然後再比較。比如
2 == '3'
就會變成2 == 3
最後會比較2 === 3
這就是最基本的規則
== 操作符具體的轉化規則
然後我們再來看看具體的轉換規則⬇️:
整體流程概覽
- 如果型別相同,呼叫
===
操作符 - 如果型別不同,嘗試型別轉換
-
- 檢視是否是
undefined
和null
比較
- ✅ 返回
true
- ⬇️ 如果不是繼續下一條規則
- 檢視是否是
-
- 是否在比較
string
和number
- ✅ 如果是,那麼將
string
轉為number
並回到最初重新比較 ♻️ - ⬇️ 如果不是繼續下一條規則
- 是否在比較
-
- 檢視我們比較的項中是否有
boolean
- ✅ 如果有,那麼將
boolean
轉為number
並回到最初重新比較 ♻️ - ⬇️ 如果不是繼續下一條規則
- 檢視我們比較的項中是否有
-
- 檢視是否有一項是
object
- ✅ 如果有,那麼將
object
轉為其原始值primitive
並回到最初重新比較 ♻️ - ❌ 如果還不是,只能返回
false
了?
- 檢視是否有一項是
舉幾個?:
![20190310173625.png](https://i.iter01.com/images/62cef6d0999ae493a44320268b48a555531f90b36828659eccae21939057acbe.png)
這麼看來轉換規則是不是很清晰明瞭?
附上一張轉換規則圖,忘記了就看看,當然正常情況下應該用 === 代替 == 避免不必要的麻煩:
![20190311001056.png](https://i.iter01.com/images/0218000712307a0bcb823c39dbad2ff90fb56f535ada8992aba86bac8190636f.png)
ecma 的規範:http://www.ecma-international.org/ecma-262/6.0/#sec-abstract-equality-comparison
型別轉換
上述在比較的過程中,涉及到型別的轉換,如字串轉整數、布林值轉整數、以及獲取物件原始值等等。瞭解一下這些不同型別之間是如何轉換的:
獲取物件原始值
接著我們再來研究一下物件怎麼轉換為原始值的:
我們需要知道轉換型別的這個方法在 JS 原始碼中是
ToPrimitive
這個方法,該方法有一個可選引數PreferredType
,這個引數的作用是指定期望型別;如果第一個引數對應的物件可以被轉換為不止一種型別,那麼後者可以作為一種暗示,表示該物件應該轉換為那種型別
-
- 預設情況下(期望型別預設為
number
)
-
- 呼叫
valueOf
方法:
- ✅ 如果返回的是原始值,那麼就用這個
- ⬇️ 如果返回的不是原始值,那麼跳到下一步
- 呼叫
-
- 呼叫
toString
方法:
- ✅ 如果返回的是原始值,那麼就用這個
- ❌ 否則報錯?
- 呼叫
- 預設情況下(期望型別預設為
-
- 如果期望型別為
string
:
-
- 呼叫
toString
方法:
- ✅ 如果返回的是原始值,那麼就用這個
- ⬇️ 如果返回的不是原始值,那麼跳到下一步
- 呼叫
-
- 呼叫
valueOf
方法:
- ✅ 如果返回的是原始值,那麼就用這個
- ❌ 否則報錯?
- 呼叫
- 如果期望型別為
-
- 如果物件是 Date 型別(期望型別為
string
):
-
- 呼叫
toString
方法:
- ✅ 如果返回的是原始值,那麼就用這個
- ⬇️ 如果返回的不是原始值,那麼跳到下一步
- 呼叫
-
- 呼叫
valueOf
方法:
- ✅ 如果返回的是原始值,那麼就用這個
- ❌ 否則報錯?
- 呼叫
- 如果物件是 Date 型別(期望型別為
簡單的說就是預設呼叫 valueOf
方法,然後是 toString
方法;如果物件是 Date
型別或物件的期望型別為 string
,那麼先呼叫 toString
方法?
舉幾個???吧:
![20190310181039.png](https://i.iter01.com/images/8bb579ef688404f625346cd70f77bcd2b687871d4c2323f51439fab54a17d751.png)
普通的物件,首先呼叫 valueOf 方法,返回的結果並非原始值,那麼會呼叫 toString 方法
![20190310181441.png](https://i.iter01.com/images/eb75e4a46c79cf7ffe557e09d4ec54eabf538588fc53145f5d3b6378b1704110.png)
假設我們重寫 valueOf 方法,valueOf 和 toString 同時返回 string 原始值。使用 == 操作符可以看出,物件還是優先使用了 valueOf 方法返回的值
![20190310181837.png](https://i.iter01.com/images/952b9b20b4d78f3b29fc6df24392edc458b28a6b14d670d215a70dd641ec743e.png)
上面的陣列同理,首先預設呼叫 valueOf 方法,如不是原始值,則呼叫 toString 方法
![20190310182219.png](https://i.iter01.com/images/64ea14879f263f27ed9cdf87dc72171647c1a9f366882f986a64016674071098.png)
這個包括眾多型別的項的陣列也是一樣?
![20190310182751.png](https://i.iter01.com/images/c6be0e8aedccf8da8297a94e5d9783ed0a1e282b21c4e0fda79e74098d2be01f.png)
再看看 Date 型別,他的期望型別是 string 因此首先呼叫的是 toString 方法,該方法返回一個原始值,那麼就是用這個原始值
轉換為 number
下面我們來看看轉換成 number 型別的規則:
undefined
?NaN
如果是 undefined 則直接轉換成 NaNnull
?0
如果是 null 則轉換成 0boolean
?0/1
如果是 boolean 則轉換成 0 或 1string
?0/NaN/(parse to number)
如果是 string 則轉換成對應的 number,空字串轉換為 0,無法轉換的則為 NaNobject
? 首先獲取原始值然後再轉為 number
看幾個?:
![20190310233718.png](https://i.iter01.com/images/8a2da1e6096d707cf042122f8e72a53ccda7f2cd5671909fc8894114714033aa.png)
轉換為 string
轉為 string 的規則為:
undefined
?'undefined'
null
?'null'
number
?'number
boolean
?'true'/'false'
object
? 首先獲取原始值,然後轉為 string
![20190310234912.png](https://i.iter01.com/images/355e4482dd6b90f5413edeabcd36c9ee59ab96d9f9c051a448e140a6c98a0a17.png)
轉為 boolean
常見的問題:哪些是 falsy 哪些是 truthy:
❌下面這些在 JS 中都為 falsy 除此之外的都是 truthy
undefined
? falsynull
? falsy0
? falsy""
? falsyNaN
? falsy
因此轉換規則如下:
undefined
?false
null
?false
number
? 當為 0 時false
否則為true
string
? 當為空字串時為false
否則為true
object
?true
array
?true
Date
?true
??是幾個例子:
![20190311000041.png](https://i.iter01.com/images/a337321df92687bbee6995fbfa4f4cdd91de659072c549dab1fbc10a12175209.png)
附上一張不同型別間轉換規則:
![20190311001627.png](https://i.iter01.com/images/08010835951a570dc5ea4bdb65aaeda2e8c0dc60ff9dfc9e2e38963dbd8440f6.png)
就寫到這裡,基本上 == 和型別轉換就是這個樣子❕
EOF
參考:
- http://www.cnblogs.com/178mz/p/5083228.html?utm_medium=referral
- http://www.ecma-international.org/ecma-262/6.0/#sec-abstract-equality-comparison
- https://www.codementor.io/javascript/tutorial/double-equals-and-coercion-in-javascript
![? 圖解 == 操作符規則和不同型別間轉換規則](https://i.iter01.com/images/98fe0b414d2ca0c30fad326b4f72399e8a6a1ddd30e4638ce5212558b7b75b9a.jpg)