寫在最前
本次分享一下通過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=。=