JavaScript "相等" 的二三事

相等不相等?

先來隨便舉幾個?吧~javascript

'0' == true          //?
[1] == [1]           //?
[1] == 1             //?
null == false        //?
null == undefined    //?
NaN === NaN          //?
+0 === -0            //?
Object.is([], [])    //?
Object.is(-0, +0)    //?
Object.is(NaN, NaN)  //?

var arr = [NaN, 0, +0]
arr.indexOf(-0)      //?
arr.indexOf(NaN)     //?
arr.includes(-0)     //?
arr.includes(NaN)    //?

可能 ±0NaN 會糾結一點,仍是比較基礎的,也許不少人一眼掃過去便知道答案了,網上也已經有了不少相關的經驗總結。我在這裏結合官方規範進行了整理,但願能帶給你不同的認識。java

預備知識

ECMAScript Language Types

傳送門。根據最新規範,EcmaScript 一共有7種語言類型:編程

  • Undefined
  • Null
  • Number
  • String
  • Boolean
  • Symbol
  • Object

咱們常常把 Object 類型稱爲 引用數據類型其它5種則爲基本數據類型。(Symbol怎麼說..?網絡

ToNumber

傳送門。任意 EcmaScript 類型轉化爲 Number 類型ecmascript

類型 結果
Undefined NaN
Null +0
Boolean true -> 1,false -> +0
Number 不轉變
String 空字符串 -> +0,有效的數字 -> 十進制數字,其它 -> NaN
Object 先ToPrimitive(hint Number),再ToNumber
Symbol 拋錯,TypeError 錯誤

ToPrimitive

傳送門。內部方法,主要功能是將引用數據類型轉化爲基本數據類型編程語言

  • 根據內部標記 hint 的不一樣有不一樣的調用順序。
  • hint有三種:defaultnumberstringdefault 默認遵守 number 規則。
  • default/number:先 valueOf,後 toString。通常轉化規則皆如此。
  • string:先 toString,後 valueOf。如Date對象方法、String()轉化等。
  • 若是 toString/valueOf 中某一方法返回類型不爲對象類型,則直接返回該值,不會繼續調用後面方法。若是二者都返回對象類型,會拋 TypeError 錯誤。

-0、+0、0 的疑惑

明明平常沒什麼卵用,爲何會有±0?編碼

  • 其實聽從IEEE754標準的編程語言都有±0的概念,IEEE754標準的64位浮點數,是以1+11+53形式的符號位+階數位+尾數位表示。
  • 符號位、階數位、尾數位都是0,那即是+0,也就是常規的數字0
  • 符號位爲1,階數位、尾數位都是0,那即是 -0
  • IEEE754還規定了NaN無窮及其它的相應規範,有興趣可自行查找相關資料。

PS

這部分實際上是後加的,你會發現每一個知識點都是緊密相連的,構成了一個龐大的知識網絡,限於篇幅我不會詳細介紹,但我會盡可能貼出規範出處,你們可自行研究。prototype

SameValueNonNumber 內部方法

SameValueNonNumber 方法接收兩個參數 x 和 y ,其中 x 和 y 都不是 Number 類型,該方法返回 truefalsecode

主要規則

  1. 斷言:x 不是 Number 類型。
  2. 斷言:x 和 y 是 相同類型。
  3. 若是 x 是 Undefined 類型,返回 true
  4. 若是 x 是 Null 類型,返回 true
  5. 若是 x 是 String 類型:對象

    • 若是 x 和 y 長度相同且相應編碼單元相同,返回 true
    • 不然返回 false
  6. 若是 x 是 Boolean 類型:

    • 若是 x 和 y 都是true 或者 都是false,返回 true
    • 不然返回 false
  7. 若是 x 是 Symbol 類型:

    • 若是 x 和 y 都是相同 Symbol 值,返回 true
    • 不然返回 false
  8. 若是 x 和 y 指向同一對象,返回 true 。不然返回 false

小結

相同類型比較規則(除Number類型)

  1. 都是 undefined,相等
  2. 都是 null,相等
  3. String 類型中,都是相同字符串,相等
  4. Boolean 類型中,都是 true 或者 都是 false,相等
  5. Symbol 類型中,都是相同 Symbol 值,相等
  6. Object 類型中,引用同一對象,相等

使用

哪些 JavaScript 公開方法採用了 SameValueNonNumber 比較呢?

  1. 公開方法木有
  2. 接着看下去你就會知道,撇開數值類型比較,SameValueNonNumberSameValueSameValueZero=== 的公共方法。

SameValueZero 內部方法

SameValueZero 方法接收兩個參數 x 和 y ,其中 x 和 y 是 EcmaScript 任意類型值,該方法返回 truefalse

主要規則

  1. 若是 x 和 y 的類型不一樣,返回 false
  2. 若是 x 是 Number 類型:

    • 若是 x 和 y 都是 NaN ,返回 true
    • 若是 x 是 -0 ,y 是 +0 ,返回 true
    • 若是 x 是 +0 ,y 是 -0 ,返回 true
    • 若是 x 和 y 數值相等,返回 true
    • 返回 false
  3. 返回 SameValueNonNumber(x, y) 方法的返回值。

小結

  1. 不一樣類型不相等
  2. Number 類型中:±0 相等。NaN 和 NaN 相等。其它相同數值相等
  3. SameValueNonNumber 比較:

    • 都是 undefined,相等
    • 都是 null,相等
    • String 類型中,都是相同字符串,相等
    • Boolean 類型中,都是 true 或者 都是 false,相等
    • Symbol 類型中,都是相同 Symbol 值,相等
    • Object 類型中,引用同一對象,相等

使用

哪些 JavaScript 公開方法採用了 SameValueZero 比較呢?

  1. Array.prototype.includes
  2. Map.prototype.delete
  3. Map.prototype.has
  4. Map.prototype.set
  5. Set.prototype.delete
  6. Set.prototype.has
  7. Set.prototype.add
  8. ArrayBuffer 和 DataView 部分方法

SameValue 內部方法

SameValue 方法接收兩個參數 x 和 y ,其中 x 和 y 是 EcmaScript 中任意類型值,該方法返回 truefalse

主要規則

  1. 若是 x 和 y 的類型不一樣,返回 false
  2. 若是 x 是 Number 類型:

    • 若是 x 和 y 都是 NaN ,返回 true
    • 若是 x 是 -0 ,y 是 +0 ,返回 false
    • 若是 x 是 +0 ,y 是 -0 ,返回 false
    • 若是 x 和 y 數值相等,返回 true
    • 返回 false
  3. 返回 SameValueNonNumber(x, y) 方法的返回值。

小結

  1. 不一樣類型不相等
  2. Number 類型中:±0 不相等。NaN 和 NaN 相等。其它相同數值相等
  3. SameValueNonNumber 比較:

    • 都是 undefined,相等
    • 都是 null,相等
    • String 類型中,都是相同字符串,相等
    • Boolean 類型中,都是 true 或者 都是 false,相等
    • Symbol 類型中,都是相同 Symbol 值,相等
    • Object 類型中,引用同一對象,相等

使用

哪些 JavaScript 公開方法採用了 SameValue 比較呢?

  1. Object.is
  2. 最新的 ES 規範 中,你會發現許多其它內部方法和公開方法都應用了 SameValue 比較方法,其中大部分也沒有涉及數值比較。
  3. 至於爲何是 SameValue 方法,而不是 SameValueZero===。其實我也不知道。。。我我的傾向於認爲:SameValue 方法本來在 ES5 規範中便存在了,最新的規範是爲了保持規範一致而繼續沿用。

=== 嚴格相等運算

Strict Equality Comparison,x === y,返回 true 或者 false

主要規則

  1. 若是 x 和 y 的類型不一樣,返回 false
  2. 若是 x 是 Number 類型:

    • 若是 x 是 NaN ,返回 false
    • 若是 y 是 NaN ,返回 false
    • 若是 x 和 y 數值相等,返回 true
    • 若是 x 是 -0 ,y 是 +0 ,返回 true
    • 若是 x 是 +0 ,y 是 -0 ,返回 true
    • 返回 false
  3. 返回 SameValueNonNumber(x, y) 方法的返回值。

小結

  1. 不一樣類型不相等
  2. Number 類型中:±0 相等。NaN 和 NaN 不相等。其它相同數值相等
  3. SameValueNonNumber比較:

    • 都是 undefined,相等
    • 都是 null,相等
    • String 類型中,都是相同字符串,相等
    • Boolean 類型中,都是 true 或者 都是 false,相等
    • Symbol 類型中,都是相同 Symbol 值,相等
    • Object 類型中,引用同一對象,相等

使用

哪些 JavaScript 公開方法採用了 === 比較呢?

  1. === 嚴格相等運算
  2. 左右兩邊是相同類型的 == 相等運算
  3. switch語句中的case
  4. Array.prototype.indexOf
  5. Array.prototype.lastIndexOf

== 相等運算

Abstract Equality Comparison,x == y,返回 true 或者 false

主要規則

  1. 若是 x 和 y 的類型相同:

    • 返回嚴格相等運算結果 x === y 。
  2. 若是 x 是 null ,y 是 undefined ,返回 true
  3. 若是 x 是 undefined ,y 是 null ,返回 true
  4. 若是 x 是 Number 類型 ,y 是 String 類型,返回 x == ToNumber(y) 運算結果。
  5. 若是 x 是 String 類型 ,y 是 Number 類型,返回 ToNumber(x) == y 運算結果。
  6. 若是 x 是 Boolean 類型 ,返回 ToNumber(x) == y 運算結果。
  7. 若是 y 是 Boolean 類型 ,返回 x == ToNumber(y) 運算結果。
  8. 若是 x 是 Number、String、Symbol 中任意一個類型 ,y 是 Object 類型,返回 x == ToPrimitive(y) 運算結果。
  9. 若是 y 是 Number、String、Symbol 中任意一個類型 ,x 是 Object 類型,返回 ToPrimitive(x) == y 運算結果。
  10. 返回 false

小結

  1. 相同類型:遵循 === 嚴格相等比較規則。
  2. null == undefined,相等
  3. 不一樣類型:

    • 基本數據類型轉換爲 Number 類型再 == 比較。
    • 引用數據類型執行內部 ToPrimitive方法後再 == 比較。

使用

哪些 JavaScript 公開方法採用了 == 比較呢?

  1. 只有這隻 == 相等運算

相等不相等

開頭的答案。若是對結果感到好奇,不妨對着上面的過程比對~

'0' == true         // false
[1] == [1]          // false
[1] == 1            // true
null == false       // false
null == undefined   // true
NaN === NaN         // false
+0 === -0           // true
Object.is([], [])   // false
Object.is(-0, +0)   // false。見SameValue
Object.is(NaN, NaN) // true。見SameValue

var arr = [NaN, 0, +0]
arr.indexOf(-0)     // 1。見===
arr.indexOf(NaN)    // -1。見===
arr.includes(-0)    // true。見SameValueZero
arr.includes(NaN)   // true。見SameValueZero

總結

  1. SameValueZeroSameValue===這仨徹底差很少嘛!

    • 相同點:

      - 不一樣類型即不相等。
      - 相同類型聽從`SameValueNonNumber`規則。
    • 不一樣點:對±0NaN 的判斷上各有不一樣。
  2. Array.prototype.includes 爲表明的SameValueZero

    • ±0 相等
    • NaN 和 NaN 相等
  3. Object.is 爲表明的SameValue

    • ±0 不相等
    • NaN 和 NaN 相等
  4. ===Array.prototype.indexOf 爲表明的===

    • ±0 相等
    • NaN 和 NaN 不相等
  5. ==

    • 相同類型採用===嚴格比較。
    • 不一樣類型會隱式轉換:

      • 基本數據類型轉換爲 Number 類型再 == 比較。
      • 引用數據類型執行 ToPrimitive 轉換後再 == 比較。
      • undefined/null 特例。
相關文章
相關標籤/搜索