null >=0 ? true:false

已禁用發表於2017-09-12

作者:Abinav Seelan 原文連結:blog.campvanilla.com/javascript-…


在掘金前端群裡(新增掘金醬:juejinjiang 入群)問了大家一個問題:

null > 0false,null == 0false,為什麼null>=0true

有說 == 不會嘗試轉型,所以 null == 0成立。但我記得不轉型的是===啊。
也有說轉換為布林值都為假,那'' == 0?
還有位群友給出了Number(null)==0的寫法,讓表示式結果為 true
但是大家都沒有正面回答問題。

開啟你的瀏覽器,按下f12,在 console 中輸入

null > 0;
null == 0;
null >= 0;複製程式碼

看看結果是什麼?
null >0 // false
null == 0// false
null >= 0 // true
神奇嗎?一個值既不大於0,也不等於0,但它居然大於或等於0
一定是我的開啟方式有問題,換個瀏覽器試試!
算了,還是查查 ECMAScript 標準吧。

抽象關係比較演算法

先看看

null > 0// false複製程式碼

根據標準,> <操作符利用抽象關係比較演算法判斷表示式為true或者false

  1. 呼叫 ToPrimitive(X, hint Number)
  2. 呼叫 ToPrimitive(y, hint Number)
  3. 如果 Type(Result(1)) 是字串且 Type(Result(2) 是字串,跳轉到步驟16。
  4. 呼叫ToNumber(Result(1))
  5. 呼叫ToNumber(Result(2))
  6. 如果Result(4)是 NaN, 返回 undefined
  7. 如果Result(5)是 NaN, 返回undefined
  8. 如果Result(4)Result(5)是同樣的數字,返回false
  9. 如果Result(4)+0而且Result(5)-0,返回false
  10. 如果Result(4)-0並且Result(5)+0,返回false
  11. 如果Result(4)+∞,返回false
  12. 如果Result(5)+∞,返回true
  13. 如果Result(5)-∞,返回false
  14. 如果Result(5)-∞,返回true
  15. 如果Result(4)數學意義上的值小於Result數學意義上的值——注意這些值都是有窮的且不都為0——返回true。否則,返回false
  16. 如果Result(2)Result(1)的字首,返回false(如果字串 q 可以由 字串 p 後跟另一個字串 r 連線組成,那麼字串 p 就是字串 q 的字首。注意任何一個字串都是其本身的字首,因為字串 r 可以是空字串)。
  17. 如果Result(1)Result(2)的字首,返回true
  18. 讓 k 是最小的非負整數,這樣Result(1)在 k 位置的字元和 Result(2)在 k 位置的字元會不一樣。(因為兩個字串都不是另一個字串的字首,所以一定存在這個 k)
  19. 讓 m 是 Result(1)中 k 位置字元的編碼值。
  20. 讓 n 是 Result(2)中 k 位置字元的編碼值。
    21.如果 m<n ,返回true。否則,返回false

null>0在整個演算法中過一遍。
步驟一與步驟二null0上呼叫ToPrimitive()分別將這兩個值轉換為原始型別(比如NumberString)。ToPrimitive的結果如下表:

Input type Result
Undefined 不轉換
Null 不轉換
Boolean 不轉換
Number 不轉換
String 不轉換
Object 轉換為物件的預設值。物件的預設值通過呼叫內部的[[DefaultValue]]方法獲得,忽略 hint 引數。

根據上表,null0都沒有轉換。

所以步驟三對我們就不適用了,跳過步驟三。步驟四與步驟五需要將左右值均轉換為Number型別。Number轉換規則如下:

Input Type Result
Undefined NaN
Null +0
Number 不轉換
Boolean true 轉為1 ,false 轉為 +0
... ...

(StringObject 的轉換省掉了,因為暫時用不上。如果你好奇可以看這個?)

null轉換為+00還是0。兩個值都不是NaN,所以步驟六與步驟七可以跳過。步驟八要注意下,+0等於0,所以演算法返回false。所以,

null > 0;//false
 and
null < 0;//alse false複製程式碼

抽象相等比較演算法

現在再來看看,
null == 0//false
這也非常有趣。

==操作符利用抽象相等比較演算法判斷true或者false

  1. 如果 Type(x)Type(y) 不一致,跳轉至步驟十四。
  2. 如果Type(x)undefined, 返回 true
  3. 如果 Type(x)Null,返回 true
  4. 如果 Type(x) 不是數字,跳轉到步驟十一。
  5. 如果 xNaN, 返回 false
  6. 如果 yNaN, 返回 false
  7. 如果 xy 是同一個數,返回 true
  8. 如果 x+0y-0,返回 true
  9. 如果 x-0y+0,返回 true
  10. 返回 false
  11. 如果 Type(x) 是字串,當 xy 是完全相同的序列時(長度一致,對應位置的字元也一樣。)返回 true。否則返回 false
  12. 如果 Type(x) 是布林值,當 xy 都為 true 或都為 false 時,語句返回 true,否則返回 false
  13. xy 指向同一個物件或指向的兩個物件是聯合物件(參見 13.1.2)時,返回 true ,否則返回 false
  14. 如果 xnullyundefined,返回 true
  15. 如果 xundefinedynull ,返回 true
  16. 如果 Type(x)NumberType(y) 是字串,返回 x == [ToNumber](http://interglacial.com/javascript_spec/a-9.html#a-9.3)(y) 的結果。
  17. 如果 Type(x)StringType(y) 是數字,返回 [ToNumber](http://interglacial.com/javascript_spec/a-9.html#a-9.3)(x)==y的結果。
  18. 如果 Type(x) 是布林值,返回 ToNumber(x) == y的結果。
  19. 如果 Type(y) 是布林值,返回 x ==ToNumber(y)的結果。
  20. 如果 Type(x) 既不是字串也不是數字而 Type(y) 是物件,返回 x == ToPrimitive(y) 的結果。
  21. 如果 Type(x) 是物件而 Type(y) 是字串或數字,返回 ToPrimitive(x) == y
  22. 返回 false

判斷 null0 是否相等,我們立刻從步驟一跳到步驟十四。因為 Type 不一樣。而且,因為Type(x) 是 null,所以步驟十四到步驟二十一也不適用。最終,步驟二十二預設返回 false。

所以,
null == 0 ; //false

大於等於操作符(>=)

現在,我們來看最後一個表示式。
null > 0;// true
這一塊標準完全把我整蒙了。從巨集觀看,>=等價於

如果 null < 0false,那麼 null>=0true

所以,
null >= 0; //true

老實說,這是有道理的。數學上講,如果兩個數字xyx 不小於 y,那麼x 必須大於或等於y

我猜這麼做的目的是為了優化比較表示式。如果可以一次比較——比較x小於y 是否成立,用這個結果推出原始表示式的結果。那幹嘛還要去先比較x 是不是大於y,如果不是,再比較x是不是等於y呢。

(如果你對>= 操作符的實際運算步驟感興趣,可以看這個)

在探索這個問題的過程中,對這門語言又有了更深的認識。希望這篇文章可以幫助你。

相關文章