JavaScript中的==,===和Object.js()
概述
本文主要講解JavaScript
中的三種相等運算:==
,===
和Object.js()
。通過對比和例子,加深大家的印象,並就個別例子進行詳細說明。
預備知識
===運算子
對於x === y
,該運算子的比較步驟如下:
- 如果
x
的型別和y
的型別不一樣,返回false
; -
如果
x
的型別是數字,那麼:- 如果
x
是NaN
,返回false
; - 如果
y
是NaN
,返回false
; - 如果
x
和y
是同一個數字值,返回true
; - 如果
x
是+0
,y
是-0
,返回true
; - 如果
x
是-0
,y
是+0
,返回true
; - 返回
false
;
- 如果
- 返回
SameValueNonNumber(x, y)
的結果。
SameValueNonNumber(x, y)
x
和y
是否相等,比較步驟如下:
- 如果
x
的型別是null
或者undefined
,返回true
; -
如果
x
是字串型別,- 如果
x
和y
是完全相同的字元編碼序列,返回true
,否則返回false
;
- 如果
-
如果
x
是布林型別,- 如果
x
和y
同為true
或者false
,返回true
,否則返回false
;
- 如果
-
如果
x
是symbol
型別,- 如果
x
和y
是相同的符號值,返回true
,否則返回false
;
- 如果
- 如果
x
和y
是同一個物件值,返回true
,否則返回false
。
需要注意的點是NaN
,+0
,-0
:
NaN === NaN // false +0 === -0 // true -0 === +0 // true
這三個例子分別對應x === y
比較步驟中的2.1
,2.4
和2.5
。這三個例子的輸出結果完全就是按照規範的定義得出的結果,沒有為什麼,規範就是這麼定義的。至於說為什麼規範要這樣定義,可能就需要去問規範的制定者了,這個就不在本文的討論範圍之內了。
Object.is()
對於Object.is(x, y)
,會使用抽象操作SameValue(x, y)
進行比較,該抽象操作的步驟如下:
- 如果
x
的型別和y
的型別不一樣,返回false
; -
如果
x
的型別是數字,那麼:- 如果
x
和y
都是NaN
,返回true
; - 如果
x
是+0
,y
是-0
,返回false
; - 如果
x
是-0
,y
是+0
,返回false
; - 如果
x
和y
是同一個數字值,返回true
- 返回
false
;
- 如果
- 返回
SameValueNonNumber(x, y)
的結果。
由此可見,===
和Object.is()
的區別在於對NaN
和帶符號的0
的處理:
NaN === NaN // false
+0 === -0 // true
-0 === +0 // true
Object.is(NaN, NaN) // true
Object.is(+0, -0) // false
Object.is(-0, +0) // false
==運算子
對於x == y
,該運算子的比較步驟如下:
- 如果
x
和y
的型別相同,返回x === y
的結果; - 如果
x
是null
,y
是undefined
,返回true
; - 如果
x
是undefined
,y
是null
,返回true
; - 如果
x
的型別是數字,y
的型別是字串,返回x == ToNumber(y)
的結果; - 如果
x
的型別是字串,y
的型別是數字,返回ToNumber(x) == y
的結果; - 如果
x
的型別是布林型別,返回ToNumber(x) == y
的結果; - 如果
y
的型別是布林型別,返回x == ToNumber(y)
的結果; - 如果
x
的型別是字串、數字或者Symbol
中的一種,y
的型別是物件,返回x == ToPrimitive(y)
的結果; - 如果
x
的型別是物件,y
的型別是字串、數字或者Symbol
中的一種,返回ToPrimitive(x) == y
的結果; - 返回
false
。
上面用到了方法ToNumber
,ToNumber(x)
的步驟如下:
- 如果
x
的型別是Undefined
,返回NaN
; - 如果
x
的型別是Null
,返回+0
; - 如果
x
的型別是布林型別,x
為true
返回1
,false
返回+0
; - 如果
x
的型別是數字,返回x
; - 如果
x
的型別是字串,參考字串轉化為數字,本文不詳細介紹這塊內容; - 如果
x
的型別是Symbol
,返回NaN
; -
如果
x
的型別是物件,- 讓
primValue
的值是ToPrimitive(x, hint Number)
; - 返回
ToNumber(primValue)
的結果;
- 讓
[] == ![]
上面講了==
運算子的比較步驟,下面我們講一個例子加深下印象:
[] == ![]
首先左邊的[]
是一個空陣列,型別是物件,右邊是![]
,[]
是一個真值,所以![]
的結果是false
:
[] == ![] // => [] == false
然後會走到x == y
比較步驟的第7
步,返回x == ToNumber(y)
的結果,也就是:
[] == false // => [] == ToNumber(false)
由ToNumber(x)
的第3
步可知,ToNumber(false)
返回+0
:
[] == ToNumber(false) // => [] == +0
然後走到x == y
比較步驟的第9
步,返回ToPrimitive(x) == y
的比較結果:
[] == +0 // => ToPrimitive([]) == +0
"" == +0
然後走到x == y
比較步驟的第5
步,返回ToNumber(x) == y
的結果:
"" == +0 // => ToNumber("") == +0
由ToNumber
操作的第5
步可知,ToNumber("")
的結果是+0
,所以也就是:
+0 == +0 // true
{} == !{}
首先,左邊是{}
,型別是物件,右邊是!{}
,{}
是真值,所以!{}
是false
:
{} == !{} // => {} == false
然後同樣會走到x == y
比較步驟的第7
步,返回x == ToNumber(y)
的結果,也就是:
{} == false // => {} == ToNumber(false)
由ToNumber(x)
的第3
步可知,ToNumber(false)
返回+0
:
{} == ToNumber(false) // => {} == +0
然後走到x == y
比較步驟的第9
步,返回ToPrimitive(x) == y
的比較結果:
{} == +0 // => ToPrimitive({}) == +0
ToPrimitive({})
的結果是字串"[object Object]"
,原因請檢視文章ECMAScript7規範中的ToPrimitive抽象操作。所以,上面等價於:
"[object Object]" == +0
然後走到x == y
比較步驟的第5
步,返回ToNumber(x) == y
的結果:
"[object Object]" == +0 // => ToNumber("[object Object]") == +0
由ToNumber
操作的第5
步可知,ToNumber("[object Object]")
的結果是NaN
,所以也就是:
NaN == +0 // false
所以,[] == ![]
的結果是true
,{} == !{}
的結果是false
。可能有人第一次看到[] == ![]
的時候,覺得這個的比較結果怎麼可能是true
。我覺得有時候不要感性的去認識問題,按照規定的運算步驟走一遍,結果是什麼就是什麼。
總結
本文講解了JavaScript
中的三種相等運算:==
,===
和Object.js()
,希望對大家有所幫助。如果本文有什麼錯誤或者不嚴謹的地方,歡迎在評論區留言。