JavaScript中的==,===和Object.is()

概述

本文主要講解JavaScript中的三種相等運算:=====Object.is()。經過對比和例子,加深你們的印象,並就個別例子進行詳細說明。segmentfault

預備知識

ECMAScript7規範中的ToPrimitive抽象操做數組

===運算符

對於x === y,該運算符的比較步驟以下:app

  1. 若是x的類型和y的類型不同,返回false
  2. 若是x的類型是數字,那麼:編碼

    1. 若是xNaN,返回false
    2. 若是yNaN,返回false
    3. 若是xy是同一個數字值,返回true
    4. 若是x+0y-0,返回true
    5. 若是x-0y+0,返回true
    6. 返回false
  3. 返回SameValueNonNumber(x, y)的結果。

SameValueNonNumber(x, y)抽象操做比較兩個非數字而且同類型的xy是否相等,比較步驟以下:code

  1. 若是x的類型是null或者undefined,返回true
  2. 若是x是字符串類型,對象

    1. 若是xy是徹底相同的字符編碼序列,返回true,不然返回false
  3. 若是x是布爾類型,ip

    1. 若是xy同爲true或者false,返回true,不然返回false
  4. 若是xsymbol類型,字符串

    1. 若是xy是相同的符號值,返回true,不然返回false
  5. 若是xy是同一個對象值,返回true,不然返回false

須要注意的點是NaN+0-0get

NaN === NaN // false
+0 === -0 // true
-0 === +0 // true

這三個例子分別對應x === y比較步驟中的2.12.42.5。這三個例子的輸出結果徹底就是按照規範的定義得出的結果,沒有爲何,規範就是這麼定義的。至於說爲何規範要這樣定義,可能就須要去問規範的制定者了,這個就不在本文的討論範圍以內了。string

Object.is()

對於Object.is(x, y),會使用抽象操做SameValue(x, y)進行比較,該抽象操做的步驟以下:

  1. 若是x的類型和y的類型不同,返回false
  2. 若是x的類型是數字,那麼:

    1. 若是xy都是NaN,返回true
    2. 若是x+0y-0,返回false
    3. 若是x-0y+0,返回false
    4. 若是xy是同一個數字值,返回true
    5. 返回false
  3. 返回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,該運算符的比較步驟以下:

  1. 若是xy的類型相同,返回x === y的結果;
  2. 若是xnullyundefined,返回true
  3. 若是xundefinedynull,返回true
  4. 若是x的類型是數字,y的類型是字符串,返回x == ToNumber(y)的結果;
  5. 若是x的類型是字符串,y的類型是數字,返回ToNumber(x) == y的結果;
  6. 若是x的類型是布爾類型,返回ToNumber(x) == y的結果;
  7. 若是y的類型是布爾類型,返回x == ToNumber(y)的結果;
  8. 若是x的類型是字符串、數字或者Symbol中的一種,y的類型是對象,返回x == ToPrimitive(y)的結果;
  9. 若是x的類型是對象,y的類型是字符串、數字或者Symbol中的一種,返回ToPrimitive(x) == y的結果;
  10. 返回false

上面用到了方法ToNumberToNumber(x)的步驟以下:

  1. 若是x的類型是Undefined,返回NaN
  2. 若是x的類型是Null,返回+0
  3. 若是x的類型是布爾類型,xtrue返回1false返回+0
  4. 若是x的類型是數字,返回x
  5. 若是x的類型是字符串,參考字符串轉化爲數字,本文不詳細介紹這塊內容;
  6. 若是x的類型是Symbol,返回NaN
  7. 若是x的類型是對象,

    1. primValue的值是ToPrimitive(x, hint Number)
    2. 返回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

ToPrimitive([])的結果是空字符串"",緣由請查看文章ECMAScript7規範中的ToPrimitive抽象操做。因此,上面等價於:

"" == +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。我以爲有時候不要感性的去認識問題,按照規定的運算步驟走一遍,結果是什麼就是什麼。

如何證實x == y比較步驟的第4步和第5步?

這個問題的詳細描述是當==運算符兩邊分別是數字和字符串類型的時候,如何證實是如步驟45描述的那般把字符串轉化成了數字,而不是把數字轉化成了字符串?

答:思路是:是否存在這樣一個例子,使得把數字轉化爲字符串後的比較結果是false,字符串轉化爲數字後的比較結果是true。是的,確實存在這樣的例子:

+'3.0' // 3 => 3 == 3 => true
'' + 3 // '3' => '3.0' == '3' // false
'3.0' == 3 // true,證實是把字符串轉化成了數字

總結

本文講解了JavaScript中的三種相等運算:=====Object.is(),但願對你們有所幫助。若是本文有什麼錯誤或者不嚴謹的地方,歡迎在評論區留言。

參考資料

  1. es7規範
相關文章
相關標籤/搜索