? 圖解 == 操作符規則和不同型別間轉換規則

JS菌發表於2019-03-10

很多人包括我在內很牴觸這種問題?,因為很長一段時間我一直弄不明白 == 和 === 到底是怎麼個規則。如果你也沒鬧明白 == 和 ===,讀了這篇文章應該至少不會見到這倆操作符就覺得噁心了吧?。

另外需要注意的是,== 的英文名叫 Abstract Equality Comparison;=== 則是 Strict Equality Comparison。

廢話不多說,我們開始搞起

== 操作符

== 操作符基本規則

首先需要注意的是

  • 如果要比較的兩個項是同種型別的,那麼 == 就會返回 === 操作符的執行結果。舉個例子? 2 == 3 最後會返回 2 === 3 的執行結果
  • 如果要比較的兩個項是不同型別的,== 就會對其中一個或兩者都進行型別轉換然後再比較。比如 2 == '3' 就會變成 2 == 3 最後會比較 2 === 3

這就是最基本的規則

== 操作符具體的轉化規則

然後我們再來看看具體的轉換規則⬇️:

整體流程概覽

  1. 如果型別相同,呼叫 === 操作符
  2. 如果型別不同,嘗試型別轉換
    1. 檢視是否是 undefinednull 比較
    • ✅ 返回 true
    • ⬇️ 如果不是繼續下一條規則
    1. 是否在比較 stringnumber
    • ✅ 如果是,那麼將 string 轉為 number 並回到最初重新比較 ♻️
    • ⬇️ 如果不是繼續下一條規則
    1. 檢視我們比較的項中是否有 boolean
    • ✅ 如果有,那麼將 boolean 轉為 number 並回到最初重新比較 ♻️
    • ⬇️ 如果不是繼續下一條規則
    1. 檢視是否有一項是 object
    • ✅ 如果有,那麼將 object 轉為其原始值 primitive 並回到最初重新比較 ♻️
    • ❌ 如果還不是,只能返回 false 了?

舉幾個?:

20190310173625.png

這麼看來轉換規則是不是很清晰明瞭?

附上一張轉換規則圖,忘記了就看看,當然正常情況下應該用 === 代替 == 避免不必要的麻煩:

20190311001056.png

ecma 的規範:http://www.ecma-international.org/ecma-262/6.0/#sec-abstract-equality-comparison

型別轉換

上述在比較的過程中,涉及到型別的轉換,如字串轉整數、布林值轉整數、以及獲取物件原始值等等。瞭解一下這些不同型別之間是如何轉換的:

獲取物件原始值

接著我們再來研究一下物件怎麼轉換為原始值的:

我們需要知道轉換型別的這個方法在 JS 原始碼中是 ToPrimitive 這個方法,該方法有一個可選引數 PreferredType,這個引數的作用是指定期望型別;如果第一個引數對應的物件可以被轉換為不止一種型別,那麼後者可以作為一種暗示,表示該物件應該轉換為那種型別

    1. 預設情況下(期望型別預設為 number
      1. 呼叫 valueOf 方法:
      • ✅ 如果返回的是原始值,那麼就用這個
      • ⬇️ 如果返回的不是原始值,那麼跳到下一步
      1. 呼叫 toString 方法:
      • ✅ 如果返回的是原始值,那麼就用這個
      • ❌ 否則報錯?
    1. 如果期望型別為 string
      1. 呼叫 toString 方法:
      • ✅ 如果返回的是原始值,那麼就用這個
      • ⬇️ 如果返回的不是原始值,那麼跳到下一步
      1. 呼叫 valueOf 方法:
      • ✅ 如果返回的是原始值,那麼就用這個
      • ❌ 否則報錯?
    1. 如果物件是 Date 型別(期望型別為 string):
      1. 呼叫 toString 方法:
      • ✅ 如果返回的是原始值,那麼就用這個
      • ⬇️ 如果返回的不是原始值,那麼跳到下一步
      1. 呼叫 valueOf 方法:
      • ✅ 如果返回的是原始值,那麼就用這個
      • ❌ 否則報錯?

簡單的說就是預設呼叫 valueOf 方法,然後是 toString 方法;如果物件是 Date 型別或物件的期望型別為 string,那麼先呼叫 toString 方法?

舉幾個???吧:

20190310181039.png

普通的物件,首先呼叫 valueOf 方法,返回的結果並非原始值,那麼會呼叫 toString 方法

20190310181441.png

假設我們重寫 valueOf 方法,valueOf 和 toString 同時返回 string 原始值。使用 == 操作符可以看出,物件還是優先使用了 valueOf 方法返回的值

20190310181837.png

上面的陣列同理,首先預設呼叫 valueOf 方法,如不是原始值,則呼叫 toString 方法

20190310182219.png

這個包括眾多型別的項的陣列也是一樣?

20190310182751.png

再看看 Date 型別,他的期望型別是 string 因此首先呼叫的是 toString 方法,該方法返回一個原始值,那麼就是用這個原始值

轉換為 number

下面我們來看看轉換成 number 型別的規則:

  1. undefined ? NaN 如果是 undefined 則直接轉換成 NaN
  2. null ? 0 如果是 null 則轉換成 0
  3. boolean ? 0/1 如果是 boolean 則轉換成 0 或 1
  4. string ? 0/NaN/(parse to number) 如果是 string 則轉換成對應的 number,空字串轉換為 0,無法轉換的則為 NaN
  5. object ? 首先獲取原始值然後再轉為 number

看幾個?:

20190310233718.png

轉換為 string

轉為 string 的規則為:

  1. undefined ? 'undefined'
  2. null ? 'null'
  3. number ? 'number
  4. boolean ? 'true'/'false'
  5. object ? 首先獲取原始值,然後轉為 string

20190310234912.png

轉為 boolean

常見的問題:哪些是 falsy 哪些是 truthy:

❌下面這些在 JS 中都為 falsy 除此之外的都是 truthy

  1. undefined ? falsy
  2. null ? falsy
  3. 0 ? falsy
  4. "" ? falsy
  5. NaN ? falsy

因此轉換規則如下:

  1. undefined ? false
  2. null ? false
  3. number ? 當為 0 時 false 否則為 true
  4. string ? 當為空字串時為 false 否則為 true
  5. object ? true
  6. array ? true
  7. Date ? true

??是幾個例子:

20190311000041.png

附上一張不同型別間轉換規則:

20190311001627.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

? 圖解 == 操作符規則和不同型別間轉換規則

相關文章