寬鬆相等(==)和嚴格相等(===)
爲什麼這個問題的討論要放在類型轉換這裏呢?
首先,這裏有一個常見的誤區,==是檢查值是否相等,===是檢查值和類型是否相等
然而JavaScript中實際上是
==允許在比較中進行強制類型轉換,而===不允許
首先在性能上,兩者差別不大(大概百萬分之一秒)
我們考慮的只有需不需要強制類型轉換這一點而已
抽象相等(==)
ES5中"抽象相等比較法"定義了==運算符的行爲
其中規定如果兩個值類型相同,就僅僅比較它們是否相等
如果兩個值類型不同,==會發生隱式強制類型轉換,會將其中之一或者兩者都轉換爲相同的類型後再比較
但是有幾個特殊情況需要注意
- NaN不等於NaN
- +0等於-0
然後還定義了對象的寬鬆相等==,兩個對象指向同一個值的時候即視爲相等(比較對象的時候==和===是完全一樣的,都不會發生強制類型轉換)
常見情況
- 字符串和數字之間的比較
- 其他類型和布爾類型之間的比較
- null和undefined之間的比較
- 對象和非對象之間的相等比較
1. 字符串和數字之間的比較
如果==運算符中有一邊是字符串,另一邊是數字
則將字符串強制轉換爲數字後進行比較
如 "42"==42 實際上是 42==42
2. 其他類型和布爾值之間的相等比較
如果==運算符中有一邊是布爾值
則將布爾值強制轉換爲數字後進行比較
"42" == true //false
3. null和undefined之間的比較
如果==運算符中有一邊是null,另一邊是undefined
則結果爲true
也就是說==中null和undefined相等(他們自身也相等)
除此之外其他值都不存在這種情況
4. 對象和非對象之間的相等比較
如果==運算符中有一方是字符串或數字(布爾值會首先被轉換爲數字)
另一方是對象(對象/函數/數組)
那麼對象首先會進行一個ToPrimitive抽象操作轉換爲對應的基本類型值
ToPrimitive抽象操作通過內部操作[[DefaultValue]]檢查是否有valueOf()方法,如果有並返回基本類型值,就使用該值進行強制類型轉換,如果沒有就使用toString()的返回值(如果存在)來進行強制類型轉換,普通對象的toString()會返回內部[[class]]的值,比如"[object Object]",而數組會將所有單元字符串化後用","連接起來,基本類型的封裝對象則會由valueOf返回基本類型值
一些例外的情況
Object(null) == null, //false
Object(undefined) == undefined, //false
Object(NaN) == NaN, //false
null和undefined沒有封裝對象,因此Object(null)返回的是Object()本身
Object(NaN)等同於new Number(NaN),但是拆封後 NaN == NaN 返回一個false值
抽象關係比較
前面說了==時候的比較規則
這裏說下a<b中涉及的隱式強制類型轉換
(該算法僅針對於a<b,a>b會被處理成b<a)
首先,比較雙方先調用ToPrivate,如果結果出現非字符串,就再調用ToNumber將雙方強制類型轉換爲數字來比較
如果雙方都是字符串,則按照字母順序來比較
但是有一點格外需要注意
JavaScript中的a<=b實際上等同於 !(a>b) 然後會被處理成!(b<a)
var a = {
num: 1
}
var b = {
num: 2
}
a > b //false
a == b //false
a < b //false
a <= b //true
a >= b //true
這個例子中a,b都被轉爲"[object Object]",因此 a<b a>b都返回false,而a<=b和a>=b都返回的是!false也就是true
但是==的時候由於兩邊都是對象並且並不指向同一個對象,因此返回false