1. 程式人生 > >JS中鮮為人知的問題: [] == ![]結果為true,而 {} == !{}卻為false

JS中鮮為人知的問題: [] == ![]結果為true,而 {} == !{}卻為false


console.log( [] == ![] )  // true
console.log( {} == !{} )  // false

在比較字串、數值和布林值的相等性時,問題還比較簡單。但在涉及到物件的比較時,問題就變得複雜了。最早的ECMAScript中的相等和不相等操作符會在執行比較之前,先將物件轉換成相似的型別。後來,有人提出了這種轉換到底是否合理的質疑。最後,ECMAScript的解決方案就是提供兩組操作符:

相等和不相等——先轉換再比較 (==)
全等和不全等——僅比較而不轉換 (===)

ECMAScript中相等操作符由兩個等於號(==)表示,如果兩個運算元相等,則返回true,這種操作符都會先轉換運算元(通常稱為強制轉型),然後再比較它們的相等性

在轉換不同的資料型別時,對於相等和不相等操作符:在JS高程中一書中給出如下的基本轉換規則

①、如果有一個運算元是布林值,則在比較相等性之前先將其轉換為數值——false轉換為0,而true轉換為1;
②、如果一個運算元是字串,另一個運算元是數值,在比較相等性之前先將字串轉換為數值
③、如果一個運算元是物件,另一個運算元不是,則呼叫物件的valueOf()方法,用得到的基本型別值按照前面的規則進行比較

這兩個操作符在進行比較時則要遵循下列規則。
①、null 和undefined 是相等的
②、要比較相等性之前,不能將null 和 undefined 轉換成其他任何值
③、如果有一個運算元是NaN,則相等操作符返回 false ,而不相等操作符返回 true。重要提示:即使兩個運算元都是NaN,相等操作符也返回 false了;因為按照規則, NaN 不等於 NaN
④、如果兩個運算元都是物件,則比較它們是不是同一個物件,如果兩個運算元都指向同一個物件,則相等操作符返回 true;否則, 返回false

在這裡插入圖片描述

這裡說一下題外話:[] 和 {} 都是屬於引用型別,引用型別是存放在棧記憶體中的,而在堆記憶體中會有一個或者多個地址來指向這個棧記憶體相對應的資料。所以在使用 == 操作符的時候,對於引用型別的資料,比較的是地址,而不是真實的值。

現在來探討 [] == ! [] 的結果為什麼會是true

①、根據運算子優先順序 ,! 的優先順序是大於 == 的,所以先會執行 ![]

!可將變數轉換成boolean型別,null、undefined、NaN以及空字串('')取反都為true,其餘都為false。

所以 ! [] 運算後的結果就是 false

也就是 [] == ! [] 相當於 [] == false

②、根據上面提到的規則(如果有一個運算元是布林值,則在比較相等性之前先將其轉換為數值——false轉換為0,而true轉換為1),則需要把 false 轉成 0

也就是 [] == ! [] 相當於 [] == false 相當於 [] == 0

③、根據上面提到的規則(如果一個運算元是物件,另一個運算元不是,則呼叫物件的valueOf()方法,用得到的基本型別值按照前面的規則進行比較,如果物件沒有valueOf()方法,則呼叫 toString()

而對於空陣列,[].toString() -> '' (返回的是空字串)

也就是 [] == 0 相當於 '' == 0

④、根據上面提到的規則(如果一個運算元是字串,另一個運算元是數值,在比較相等性之前先將字串轉換為數值

Number('') -> 返回的是 0

相當於 0 == 0 自然就返回 true了

總結一下:

[] == ! [] -> [] == false -> [] == 0 -> '' == 0 -> 0 == 0 -> true

那麼對於 {} == !{} 也是同理的

關鍵在於 {}.toString() -> NaN(返回的是NaN)

根據上面的規則(如果有一個運算元是NaN,則相等操作符返回 false

總結一下:

{} == ! {} -> {} == false -> {} == 0 -> NaN == 0 -> false

那麼相信大家對下面的兩道題就信手拈來了


console.log( [] == !{} ) // true
console.log( {} == ![] ) // false

本文屬於magic_xiang原創,轉載需註明來源

來源:https://segmentfault.com/a/1190000017571299