標籤:

精讀《null >= 0?》

本期精讀的文章是:null >= 0?

1 引言

你是如何看待 null >= 0 為 true 這個結果的呢?要麼選擇勉強接受,要麼跟著我一探究竟吧。

2 內容概要

大於判斷

javascript 在判斷 a > b 時,記住下面 21 步判斷法:

  1. 調用 b 的 ToPrimitive(hit Number) 方法.
  2. 調用 a 的 ToPrimitive(hit Number) 方法.
  3. 如果此時 Result(1) 與 Result(2) 都是字元串,跳到步驟 16.
  4. 調用 ToNumber(Result(1)).
  5. 調用 ToNumber(Result(2)).
  6. 如果 Result(4) 為 NaN, return undefined.
  7. 如果 Result(5) 為 NaN, return undefined.
  8. 如果 Result(4) 和 Result(5) 是相同的數字,return false.
  9. 如果 Result(4) 為 +0, Result(5) 為 -0, return false.
  10. 如果 Result(4) 為 -0, Result(5) 為 +0, return false.
  11. 如果 Result(4) 為 +∞, return false.
  12. 如果 Result(5) 為 +∞, return true.
  13. 如果 Result(5) 為 -∞, return false.
  14. 如果 Result(4) 為 -∞, return true.
  15. 如果 Result(4) 的數值大小小於 Result(5),return true,否則 return false.
  16. 如果 Result(2) 是 Result(1) 的前綴 return false. (比如 "ab" 是 "abc" 的前綴)
  17. 如果 Result(1) 是 Result(2) 的前綴, return true.
  18. 找到一個位置 k,使得 a[k] 與 b[k] 不相等.
  19. 取 m 為 a[k] 字元的數值.
  20. 取 n 為 b[k] 字元的數值.
  21. 如果 m < n, return true,否則 return false.

ToPrimitive 會按照順序優先使用存在的值:valueOf()、toString(),如果都沒有,會拋出異常。 ToPrimitive(hit Number) 表示隱轉數值類型

所以 null > 0 結果為 false。

等於判斷

現在看看 a == b 時的表現(三等號會嚴格判斷類型,兩等號反而是最複雜的情況)。

  1. 如果 a 與 b 的類型相同,則:
  • 如果 Type(b) 為 undefined,return true.
  • 如果 Type(b) 為 null,return true.
  • 如果 Type(b) 為 number,則:
    • 如果 b 為 NaN,return false.
    • 如果 a 為 NaN,return false.
    • 如果 a 與 b 數值相同,return true.
    • 如果 a 為 +0,b 為 -0,return true.
    • 如果 a 為 -0,b 為 +0,return true.
    • 否則 return false.
  • 如果 Type(b) 為 string,且 a 與 b 是完全相同的字元串,return true,否則 return false.
  • 如果 Type(b) 是 boolean,如果都是 true 或 false,return true,否則 return false.
  • 如果 a 與 b 是同一個對象引用,return true,否則 return false.
  1. 如果 a 為 null,b 為 undefined,return true.
  2. 如果 a 為 undefined,b 為 null,return true.
  3. 如果 Type(a) 為 number,Type(b) 為 string,返回 a == ToNumber(b) 的結果.
  4. 如果 Type(a) 為 string,Type(b) 為 number,返回 ToNumber(a) == b 的結果.
  5. 如果 Type(a) 為 boolean,返回 ToNumber(a) == b 的結果.
  6. 如果 Type(b) 為 boolean,返回 a == ToNumber(b) 的結果.
  7. 如果 Type(a) 是 string 或 number,且 Type(b) 是對象類型,返回 a == ToPrimitive(b) 的結果.
  8. 如果 Type(a) 是對象類型,且 Type(b) 是 string 或 number,返回 ToPrimitive(a) == b 的結果.
  9. 否則 return false.

所以 null == 0 走到了第 10 步,返回了默認的 false。

大於等於判斷

javascript 是這麼定義大於等於判斷的:

如果 a < b 為 false,則 a >= b 為 true

所以 null >= 0 為 true,因為 null < 0 是 false.

3 精讀

關於 toPrimitive

拓展一下,我們可以通過 Symbol.toPrimitive 定義某個 class 的 ToPrimitive 行為,比如:

class AnswerToLifeAndUniverseAndEverything {n [Symbol.toPrimitive](hint) {n if (hint === string) {n return Like, 42, man;n } else if (hint === number) {n return 42;n } else {n // when pushed, most classes (except Date)n // default to returning a number primitiven return 42;n }n }n}n

還有不按套路出牌的情況?

按上面的道理,我們可以舉一反三:

{} >= {} // truen

可是這是為何呢?

null >= {} // falsen

仔細讀過上文應該不難發現,如果 ToPrimitive(hit Number) 出現了 NaN,將直接 return undefined,也就是列印出 false,而下面是隱式轉換表,{} 的結果是 NaN,因此結果是 false。

4 總結

NaN 在 javascript 是個特殊存在,只有 isNaN 可以準確判斷到它,而且使用它進行比較判斷時,會直接 return false.

javascript 隱式轉換有一套優先順序規則,而且不同值的隱式轉換還需要對照表記憶,還存在 ToPrimitive(hint Number)ToPrimitive(hint String) ToPrimitive(hint Boolean) 三份表,記憶起來確實有點複雜。

因此推薦比較判斷時,盡量使用 ===,通過 Typescript Flow 等強類型語言約束變數類型,盡量不要做不同類型變數間的比較。

討論地址是:精讀《null >= 0?》 · Issue #36 · dt-fe/weekly

如果你想參與討論,請點擊這裡,每周都有新的主題,每周五發布。

推薦閱讀:

【Web系列】小說在線閱讀
JS trick之babel-stage語法雜談
極樂技術周報(第十八期)
作為前端負責人,團隊成員工作自己不能分配,前端工作又要我協調,好痛苦?

TAG:前端开发 |