很多人包括我在內很牴觸這種問題?,因為很長一段時間我一直弄不明白 == 和 === 到底是怎麼個規則。如果你也沒鬧明白 == 和 ===,讀了這篇文章應該至少不會見到這倆操作符就覺得噁心了吧?。
另外需要注意的是,== 的英文名叫 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
了?
- 檢視是否有一項是
舉幾個?:
這麼看來轉換規則是不是很清晰明瞭?
附上一張轉換規則圖,忘記了就看看,當然正常情況下應該用 === 代替 == 避免不必要的麻煩:
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
方法?
舉幾個???吧:
普通的物件,首先呼叫 valueOf 方法,返回的結果並非原始值,那麼會呼叫 toString 方法
假設我們重寫 valueOf 方法,valueOf 和 toString 同時返回 string 原始值。使用 == 操作符可以看出,物件還是優先使用了 valueOf 方法返回的值
上面的陣列同理,首先預設呼叫 valueOf 方法,如不是原始值,則呼叫 toString 方法
這個包括眾多型別的項的陣列也是一樣?
再看看 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
看幾個?:
轉換為 string
轉為 string 的規則為:
undefined
?'undefined'
null
?'null'
number
?'number
boolean
?'true'/'false'
object
? 首先獲取原始值,然後轉為 string
轉為 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
??是幾個例子:
附上一張不同型別間轉換規則:
就寫到這裡,基本上 == 和型別轉換就是這個樣子❕
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