精讀《null >= 0?》
本期精讀的文章是:null >= 0?
1 引言
你是如何看待 null >= 0 為 true 這個結果的呢?要麼選擇勉強接受,要麼跟著我一探究竟吧。
2 內容概要
大於判斷
javascript 在判斷 a > b 時,記住下面 21 步判斷法:
- 調用 b 的 ToPrimitive(hit Number) 方法.
- 調用 a 的 ToPrimitive(hit Number) 方法.
- 如果此時 Result(1) 與 Result(2) 都是字元串,跳到步驟 16.
- 調用 ToNumber(Result(1)).
- 調用 ToNumber(Result(2)).
- 如果 Result(4) 為 NaN, return undefined.
- 如果 Result(5) 為 NaN, return undefined.
- 如果 Result(4) 和 Result(5) 是相同的數字,return false.
- 如果 Result(4) 為 +0, Result(5) 為 -0, return false.
- 如果 Result(4) 為 -0, Result(5) 為 +0, return false.
- 如果 Result(4) 為 +∞, return false.
- 如果 Result(5) 為 +∞, return true.
- 如果 Result(5) 為 -∞, return false.
- 如果 Result(4) 為 -∞, return true.
- 如果 Result(4) 的數值大小小於 Result(5),return true,否則 return false.
- 如果 Result(2) 是 Result(1) 的前綴 return false. (比如 "ab" 是 "abc" 的前綴)
- 如果 Result(1) 是 Result(2) 的前綴, return true.
- 找到一個位置 k,使得 a[k] 與 b[k] 不相等.
- 取 m 為 a[k] 字元的數值.
- 取 n 為 b[k] 字元的數值.
- 如果 m < n, return true,否則 return false.
ToPrimitive 會按照順序優先使用存在的值:valueOf()、toString(),如果都沒有,會拋出異常。 ToPrimitive(hit Number) 表示隱轉數值類型
所以 null > 0 結果為 false。
等於判斷
現在看看 a == b 時的表現(三等號會嚴格判斷類型,兩等號反而是最複雜的情況)。
- 如果 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.
- 如果 a 為 null,b 為 undefined,return true.
- 如果 a 為 undefined,b 為 null,return true.
- 如果 Type(a) 為 number,Type(b) 為 string,返回 a == ToNumber(b) 的結果.
- 如果 Type(a) 為 string,Type(b) 為 number,返回 ToNumber(a) == b 的結果.
- 如果 Type(a) 為 boolean,返回 ToNumber(a) == b 的結果.
- 如果 Type(b) 為 boolean,返回 a == ToNumber(b) 的結果.
- 如果 Type(a) 是 string 或 number,且 Type(b) 是對象類型,返回 a == ToPrimitive(b) 的結果.
- 如果 Type(a) 是對象類型,且 Type(b) 是 string 或 number,返回 ToPrimitive(a) == b 的結果.
- 否則 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:前端开发 |