關於null>=0為true
我們先從一組 用例說起. 看程式碼:
null > 0 // false
null == 0 // false
null >= 0 //true
我們今天討論的主要內容,並不是這個結果可能看起來多麼奇怪. 而是為什麼會這樣. 之所以特別記一篇隨筆在這裡,主要是因為,我在得到了Brendan Eich 的一些確認後.發現答案和我當初的猜測不一樣. 所以我有反省,自己對ES的一些理解上,是不是有些偏主觀.
開始前,我們先拿ES3,ES5的相關定義說起:
注1 : ES3,ES5對關係運算符 ">" , "<", ">=", "<=" 以及相等運算子的實現,在關鍵部分幾乎相同,所以不再列出ES5的內容.
注2 : 下面這些內容,你只需要簡單注意下,我標紅的部分,其他部分其實無關緊要. 我會對這些內容,在後面的部分有個大概的解釋.
注3 : <= 以及 < 與之類似,不在贅述..
說明
1. 關係運算符 和 相等運算子 並不是一個類別的.
2. 關係運算符,在設計上,總是需要運算元嘗試轉為一個number . 而相等運算子在設計上,則沒有這方面的考慮.
3. 最重要的一點, 不要把 拿 a > b , a == b 的結果 想當然的去和 a >= b 建立聯絡. 正確的符合最初設計思想的關係是 a > b 與 a >= b是一組 . a == b 和其他相等運算子才是一組. 比如 a === b , a != b, a !== b .
所以,我們反過來看待這個問題.
null > 0 // null 嘗試轉型為number , 則為0 . 所以結果為 false,
null >= 0 // null 嘗試轉為number ,則為0 , 結果為 true.
null == 0 // null在設計上,在此處不嘗試轉型. 所以 結果為false.
我個人在之前的閱讀中,並沒有意識到這些問題.而導致,我愚蠢的認為, >= 的結果是設計上的失誤. 原因是,我簡單的認為 :
Perform the comparison Result(2) < Result(4). (see 11.8.5).
If Result(5) is true or undefined, return false. Otherwise, return true.
a >= b 運算子只是簡單的去對 a < b的結果取反. 我以為這是一個設計上的失誤的另一個理由是 undefined,在標準中,被單拎出來.細心的你,也一定發現了這一點. 對於undefined的設計, undefined > 0 , undefined < 0, undefined == 0 的結果是符合設計上,邏輯的一致性的. 而null是被遺漏的東西.
懷著這樣的想法,我給es-discuss 寫了信,用不溫和的口吻.質疑這個問題. 驚喜的是,Brendan Eich 居然關注了這個問題.並立刻做出了回覆. 悲劇的是,我在反覆閱讀該回信內容時,仍然沒有從根本上理解到這個問題.直到今天早上.我重新翻閱了ES3,5.相關章節. 才恍然大悟.
到此,我的反省結束. 同時也感謝 BE 的認真,及時的回覆. 作為一個CTO,任然如此關心並積極參與技術社群的發展,實在讓人欽佩.
廣州品牌設計公司https://www.houdianzi.com PPT模板下載大全https://redbox.wode007.com
接著是吐槽的時候了:
雖然前面的例子,我catch到了BE當初的設計思想. 但是從全域性的角度來看. 從關係運算符到相等運算子,尤其是相等運算子的設計上. 真的十分混亂不堪. BE在信中提到,他對 == 的現狀也很無奈. 甚至用愚蠢這個詞來形容自己當初的實現(當然他還提到,當初只是為了在10天內設計出js,並跑過qa的測試用例). 即使如此, 但是他仍然表示 null == 0 這個結果是他想要的.
好吧,到了這裡,我也有種無力感. 我認為縱觀JavaScript,對關係運算和相等運算的設計.除了混亂,我想不出還有什麼詞來形容它們更恰當. 這一點從,我們生產環境程式碼中,大量的型別檢查,和防禦性程式碼的的存在,就可以證明這一點.
另外一個要吐槽的地方是ES規範本身. 比如前面讓我深深誤解的地方 ,即 a >= b 即 對 a < b 的結果取反. 這一點上,就屬於不明確表述. 我們想想一個典型的js的例子
function case1(a){
if(a == null){
....
}
}
function case2(a){
if(a == undefined){
...
}
}
// 上面兩組完全等價, 這就是一種不明確表述.
// 我們永遠不知道程式碼編寫者的目的到底是同時匹配null 和 undefined還是隻匹配其中某一個
function case3(a){
if(a === null || a === undefined){
...
}
}
// case3 才是最好的表述. 我們明確知道程式碼編寫者的意圖.
// 即使很多人可能認為這個程式碼很愚蠢. 但我堅定的認為這才是好程式碼.
所以寫程式碼,寫規範,都應該明確表述. 即使表述的很羅嗦,但不會引起歧義或懷疑. 這才是一份好的標準.文件,程式碼. 而避免歧義,和各種混亂不堪的規則,是一門語言最應遵守的設計原則.
最後, 不得不提到,我發出null >= 0 這封信後,Andrea Giammarchi 表示了對我之前看法的支援,他同我最初的看法一樣,認為 null >= 0 的結果應該為 false . 並建議在 ES7 中的嚴格模式中,修改這個結果. 雖然同樣遭到David Bruant 的反對. 好吧為他和我的這個錯誤看法,默哀一分鐘...