作者:Abinav Seelan 原文連結:blog.campvanilla.com/javascript-…
在掘金前端群裡(新增掘金醬:juejinjiang 入群)問了大家一個問題:
null > 0
為false
,null == 0
為false
,為什麼null>=0
為true
?
有說 ==
不會嘗試轉型,所以 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
。
- 呼叫
ToPrimitive(X, hint Number)
。- 呼叫
ToPrimitive(y, hint Number)
。- 如果
Type(Result(1))
是字串且Type(Result(2)
是字串,跳轉到步驟16。- 呼叫
ToNumber(Result(1))
。- 呼叫
ToNumber(Result(2))
。- 如果
Result(4)
是 NaN, 返回undefined
。- 如果
Result(5)
是 NaN, 返回undefined
。- 如果
Result(4)
和Result(5)
是同樣的數字,返回false
。- 如果
Result(4)
是+0
而且Result(5)
是-0
,返回false
。- 如果
Result(4)
是-0
並且Result(5)
是+0
,返回false
。- 如果
Result(4)
是+∞
,返回false
。- 如果
Result(5)
是+∞
,返回true
。- 如果
Result(5)
是-∞
,返回false
。- 如果
Result(5)
是-∞
,返回true
。- 如果
Result(4)
數學意義上的值小於Result
數學意義上的值——注意這些值都是有窮的且不都為0——返回true
。否則,返回false
。- 如果
Result(2)
是Result(1)
的字首,返回false
(如果字串 q 可以由 字串 p 後跟另一個字串 r 連線組成,那麼字串 p 就是字串 q 的字首。注意任何一個字串都是其本身的字首,因為字串 r 可以是空字串)。- 如果
Result(1)
是Result(2)
的字首,返回true
。- 讓 k 是最小的非負整數,這樣
Result(1)
在 k 位置的字元和Result(2)
在 k 位置的字元會不一樣。(因為兩個字串都不是另一個字串的字首,所以一定存在這個 k)- 讓 m 是
Result(1)
中 k 位置字元的編碼值。- 讓 n 是
Result(2)
中 k 位置字元的編碼值。
21.如果m<n
,返回true
。否則,返回false
。
將null>0
在整個演算法中過一遍。
步驟一與步驟二 在null
和0
上呼叫ToPrimitive()
分別將這兩個值轉換為原始型別(比如Number
和String
)。ToPrimitive
的結果如下表:
Input type | Result |
---|---|
Undefined | 不轉換 |
Null | 不轉換 |
Boolean | 不轉換 |
Number | 不轉換 |
String | 不轉換 |
Object | 轉換為物件的預設值。物件的預設值通過呼叫內部的[[DefaultValue]]方法獲得,忽略 hint 引數。 |
根據上表,null
和0
都沒有轉換。
所以步驟三對我們就不適用了,跳過步驟三。步驟四與步驟五需要將左右值均轉換為Number
型別。Number
轉換規則如下:
Input Type | Result |
---|---|
Undefined | NaN |
Null | +0 |
Number | 不轉換 |
Boolean | true 轉為1 ,false 轉為 +0 |
... | ... |
(String
及 Object
的轉換省掉了,因為暫時用不上。如果你好奇可以看這個?)
null
轉換為+0
而0
還是0
。兩個值都不是NaN
,所以步驟六與步驟七可以跳過。步驟八要注意下,+0
等於0
,所以演算法返回false
。所以,
null > 0;//false
and
null < 0;//alse false複製程式碼
抽象相等比較演算法
現在再來看看,null == 0//false
這也非常有趣。
==
操作符利用抽象相等比較演算法判斷true
或者false
。
- 如果
Type(x)
與Type(y)
不一致,跳轉至步驟十四。- 如果
Type(x)
是undefined
, 返回true
。- 如果
Type(x)
是Null
,返回true
。- 如果
Type(x)
不是數字,跳轉到步驟十一。- 如果
x
是NaN
, 返回false
。- 如果
y
是NaN
, 返回false
。- 如果
x
和y
是同一個數,返回true
。- 如果
x
是+0
且y
是-0
,返回true
。- 如果
x
是-0
且y
是+0
,返回true
。- 返回
false
。- 如果
Type(x)
是字串,當x
與y
是完全相同的序列時(長度一致,對應位置的字元也一樣。)返回true
。否則返回false
。- 如果
Type(x)
是布林值,當x
與y
都為true
或都為false
時,語句返回true
,否則返回false
。- 當
x
與y
指向同一個物件或指向的兩個物件是聯合物件(參見 13.1.2)時,返回true
,否則返回false
。- 如果
x
是null
且y
是undefined
,返回true
。- 如果
x
是undefined
且y
是null
,返回true
。- 如果
Type(x)
是Number
且Type(y)
是字串,返回x == [ToNumber](http://interglacial.com/javascript_spec/a-9.html#a-9.3)(y)
的結果。- 如果
Type(x)
是String
且Type(y)
是數字,返回[ToNumber](http://interglacial.com/javascript_spec/a-9.html#a-9.3)(x)==y
的結果。- 如果
Type(x)
是布林值,返回ToNumber(x) == y
的結果。- 如果
Type(y)
是布林值,返回x ==ToNumber(y)
的結果。- 如果
Type(x)
既不是字串也不是數字而Type(y)
是物件,返回x == ToPrimitive(y)
的結果。- 如果
Type(x)
是物件而Type(y)
是字串或數字,返回ToPrimitive(x) == y
。- 返回
false
。
判斷 null
與 0
是否相等,我們立刻從步驟一跳到步驟十四。因為 Type 不一樣。而且,因為Type(x) 是 null,所以步驟十四到步驟二十一也不適用。最終,步驟二十二預設返回 false。
所以,null == 0 ; //false
大於等於操作符(>=)
現在,我們來看最後一個表示式。null > 0;// true
這一塊標準完全把我整蒙了。從巨集觀看,>=
等價於
如果
null < 0
是false
,那麼null>=0
是true
。
所以,null >= 0; //true
老實說,這是有道理的。數學上講,如果兩個數字x
和y
,x
不小於 y
,那麼x
必須大於或等於y
。
我猜這麼做的目的是為了優化比較表示式。如果可以一次比較——比較x
小於y
是否成立,用這個結果推出原始表示式的結果。那幹嘛還要去先比較x
是不是大於y
,如果不是,再比較x
是不是等於y
呢。
(如果你對>=
操作符的實際運算步驟感興趣,可以看這個)
在探索這個問題的過程中,對這門語言又有了更深的認識。希望這篇文章可以幫助你。