寫在最前
本次分享一下通過ES5規範來總結如何準確的計算“==”的執行結果。由於規範是枯燥無味的,所以作者試圖總結了其中的規律,並希望可以讓讀完這篇文章的讀者不再去“死記硬背”==的結果是什麼,而是通過幾次簡單的計算便心有成竹的得出結論!
歡迎關注我的部落格,不定期更新中——
JavaScript小眾系列開始更新啦
——何時完結不確定,寫多少看我會多少!這是已經更新的地址:
- 小眾系列之終極型別轉換:從hello world看JavaScript隱藏的黑魔法制
- 小眾系列之隱式型別轉換:從[] == ![]看隱式強制轉換機制
- 小眾系列之事件迴圈:從HTML5與PromiseA+規範來看事件迴圈
這個系列旨在對一些人們不常用遇到的知識點,以及可能常用到但不曾深入瞭解的部分做一個重新梳理,雖然可能有些部分看起來沒有什麼用,因為平時開發真的用不到!但個人認為糟粕也好精華也罷裡面全部蘊藏著JS一些偏本質的東西或者說底層規範,如果能適當避開舒適區來看這些小細節,也許對自己也會有些幫助~文章更新在我的部落格,歡迎不定期關注。
先看實驗程式碼
2 == true //false
2 == false //false
[] == false //true
"0" == false //true
[] == ![] //true 神奇吧複製程式碼
我相信大部分的童鞋看著這種等式一般的反應都是xxx是真值,可以轉換為true。xxx是假的所以是false!好的摒棄這種想法吧,不然也不會出現這麼多神奇的結果了,我們需要做的是通過一步步計算來得出結論。
前置知識
這部分知識屬於真·死記硬背,因為你問我為什麼,我只能說規範就是這麼定義的。
假值
為什麼提到假值,而不是真值是因為真值真的是太!多!了!但是假值只有以下這麼幾個:
- undefined
- null
- false
- +0、-0、NaN
- ""
除此以外別的值做強制型別轉換的時候都是真值,so記住就好。
PS:有興趣的同學可以試試new Number(0)
之類的通過物件包裝的假值的結果,不過這並不常用故不屬於本次討論範疇。
!
! 這個運算子,會進行顯式強制轉化,將結果轉化為布林值即true或false。例如:
![] //false
!1 //false
!0 //true複製程式碼
以此類推來進行顯式的強制轉換
undefined == null
參考規範11.9.3節抽象相等比較演算法可得出
undefined == null 為true的結論。
PS:本次計算規則為抽象相等比較演算法的總結,細節可參考上文11.9.3節規範。
ToPrimitive
這是規範9.1節的內容,簡單來說你只需要知道如果某個物件([], {})之類的要進行隱式型別轉換,那麼裡面會順序執行兩個操作。即
x.valueOf().toString()
。這裡有一個不常用的點要注意。我說的是物件型別進行“隱式”型別轉化,如果是顯式則不是如此。看下例子:
var a = {
valueOf: () => 1,
toString: () => 233
}
a + "" // 1
String(a) // 233複製程式碼
隱式轉化是按照先valueOf後toString的順序執行,如果顯式呼叫會直接執行oString,不過顯式呼叫在js中覆蓋率沒有隱式的多,知道即可。
計算 x == y 規則
x,y如果型別相同
這個部分相信有問題的同學百度一下就好。數字的比大小,字串比大小。裡面需要小心的就是NaN != NaN 以及 物件如何比較大小?([1] != [1])
重點:x,y型別不同
x,y一方為布林值
如果x,y其中一個是布林值,那麼對這個布林值進行toNumber操作。發現問題了麼童鞋們,來看下面程式碼:
42 == true // false複製程式碼
不瞭解規範的會認為,42是真值啊!42會轉換為true!你別說如if(42){}
這個42確實是真值。但是我們現在在討論“==”下的轉換,那麼請記住規範規定了:型別不同時若一方是布林值,是對布林值進行型別轉化即true => 1
,之後我們就可以理解為什麼42不等於true了因為1!= 42
x,y為數字和字串
將字串的一方進行toNumber()操作,這個不難理解哈
x,y一方為物件
將物件進行ToPrimitive()操作。如何操作見上文。
計算示例程式碼結果
2 == true
true => 一方為布林值:true => 1
2 != 1複製程式碼
2 == false
true => 一方為布林值:false => 0
2 != 0複製程式碼
[] == false
1、[]為物件: ToPrimitive([]) => [].valueOf().toString() => ""
2、false為布林:false => 0
3、等式變為:"" == 0
4、一方為數字,一方為字元
Number("") => 0
=> 0 == 0複製程式碼
"0" == false
1、false為布林:false => 0
2、等式變為:"0" == 0
3、一方為數字,一方為字元
Number("0") => 0
=> 0 == 0複製程式碼
終極版 [] == ![]
1、左側[]為物件: ToPrimitive([]) => [].valueOf().toString() => ""
2、右側![]先進行顯式型別轉換:false(除了上文提到的假值剩下都是真值)
3、等式變為: "" == false
4、一方為布林:false => 0
5、等式變為:"" == 0
5、一方為數字,一方為字元
Number("") => 0
=> 0 == 0複製程式碼
所以你會發現這些看起來神奇的效果,不過是一步步按照規則進行強制轉換罷了。希望以後大家再遇到這種神奇等式的時候不要靠記憶誰是誰,而是一步步推算你會發現結果也不過如此,扮豬吃老虎罷了~
參考文獻
最後
慣例po作者的部落格,不定時更新中——
有問題歡迎在issues下交流,捂臉求star=。=