原文地址:落明的部落格,轉載請註明出處!
一、前言
作為一個程式設計師,我想大家在第一次看到 a = b
的語句時一定是懵逼的。後來才知道 =
在程式語言中是用來賦值的,而不是用來判斷兩個值是否相等。
那該怎麼判斷兩個值是否相等呢?在 C 或 java 中,是使用 ==
來進行比較,而 JavaScript 就有意思了,除了使用 ==
, 還加了 ===
。
二、區別與選擇
-
它們有什麼區別?
具體的區別就一句話:
==
在比較時允許進行強制型別轉換,而===
不允許。很多人都擔心
==
做的事情多一些會不會影響比較的速度,說實話,會的,但影響是微秒級別的,完全可以忽略不計。不難看出,
==
像是===
的一種更深入的擴充套件,因此,滿足===
的值一定滿足==
,反之則不成立。 -
該如何選擇使用它們?
很多人會建議你堅持使用
===
而不使用==
, 我認為這是不明智的,有些時候,比如說處理後端返回的資料時,你無法保證對方傳來的值到你進行比較的時候還是預期的那樣,此時我覺得完全在可以適當的使用==
來進行相容。總的來說,當你真的確定進行比較的值是型別相同的,那就使用
===
,否則,除了幾種特殊情況,使用==
並沒有什麼問題 。
三、===
的比較規則
-
基本型別值的比較
===
的比較規則很簡單,對於非物件型別的值,先判斷兩邊的運算元是否是同一型別,如果是,則進行比較,否則,直接返回false
。但有兩個例外情況:
NaN === NaN
和+0 === -0
。// 不同型別 '12' === 12; // false 'a' === true; // false null === '12' // false null === undefined; // false // 同型別 1 === 1; // true 'a' === 'a'; // true false === false; // true null === null; // true //特殊情況 NaN === NaN; // false +0 === -0 // true 複製程式碼
-
引用型別值的比較
對於包含引用型別值的比較,仍然會先判斷兩邊的資料型別,如果只有一個是引用型別值,則直接返回
false
,如果兩邊均是引用型別值,則會比較他們的引用地址是否一致。const a = { m: 'string', n: 12 }; const b = { m: 'string', n: 12 }; const c = 12; a === b; // false a === c ; // false const d = a; a === d; // true 複製程式碼
四、==
的比較規則
一開始說過了,在使用 ==
進行比較時,執行對兩邊的運算元進行強制型別轉換,那麼問題來了,什麼情況下會進行轉換?不同型別的轉換規則又是怎樣?
在 MDN
中有這樣一張表,用來展示不同型別值進行 ==
判斷時的轉換規則。
乍一看可能會覺得很亂,但仍然是可以分幾種情況來概括這些情況。
在具體分析之前,建議先閱讀上一篇文章 顯式 (名義) 與 隱式 (鴨子)型別轉換
,因為上圖中你能看到有諸如 isFalsy()
、ToNumber()
、ToString()
、ToPrimitive
等抽象方法,使用它們只是為了讓大家知道強制轉換的方向和結果,而這些也都是上一篇文章講到的內容。
-
Undefined
和Null
與其它型別值的比較我們看前兩行和前兩列可以發現:它們只和自身及對方相等,與其他型別值比較均返回
false
。 ....這個大概就是傳說中的「黑風雙煞」吧!大家可能會看到
Object
有一個isFalse()
方法,這個方法是用來判斷引數值是否是假值,這個時候大家可能會有疑問了,物件不是都是真值嗎?沒錯,
document.all
就是一個假值物件,雖然已經被新的 JavaScript 標準廢棄,但你或許會在老的專案中看到它,記住就好。由於這倆值的特殊性,後面我們說“其他型別”值的時候是排除這倆型別的。
-
Number
型別值與其他型別值比較除了上面的黑風雙煞,
Number
算是相等比較時的大哥,誰想和它比較,就得先轉成Number
型別。 -
Boolean
型別值與其他型別值比較既然有大哥,肯定得有小弟,而
Boolean
型別值則一馬當先,以身作則,將大哥的原則貫徹到底,堪稱模範小弟!其他型別值想和
Boolean
值做比較,Boolean
值搖身一變將自己轉成了Number
型別,哎,你說,別人能怎麼辦?!無論別人怎麼說,
Boolean
只想做一隻安靜的舔狗,無怨無悔,一生一世。 -
Object
型別值與其他型別值比較Object
作為 JavaScript 中最會偽裝自己的一種型別,在比較之前誰也摸不透它們的真實身份。也正因為此,它們的日子過得不盡相同。在進行比較時,JavaScript 國王會通過
toPrimitive()
方法來揭開他們的真面目,最終你會發現,它們的真實身份可能是任意的一種基本型別。因此,在最終比較時,它們也將以真實身份與其他型別值比較。
-
String
型別值與其他型別值比較對於
String
型別值來說,在進行比較時的日子並不好過,畢竟,黑風雙煞惹不起,黑社會說話也得聽,唯一能讓它感受到生活希望的,就是在與Object
這個變色龍進行比較的時候了。只有
Object
在toPrimitive()
後轉為字串的時候它們可以以字串的規則進行比較,否則,它們就要面臨黑風雙煞或是黑社會。
五、==
正確的使用方法
github 上有位大神總結了下面這張圖:
我們可以將此當做一份參考。
其實在實際的使用過程中,只要我們避免一些特殊的情況,==
的使用還是安全的。
下面就是七種所謂的特殊情況。
"0" == false; // true -- 暈!
false == 0; // true -- 暈!
false == ""; // true -- 暈!
false == []; // true -- 暈!
"" == 0; // true -- 暈!
"" == []; // true -- 暈!
0 == []; // true -- 暈!
複製程式碼
如何避免?兩個原則:
- 如果兩邊的值中有 true 或者 false,千萬不要使用 ==。
- 如果兩邊的值中有 []、"" 或者 0,儘量不要使用 ==。
六、最後
檢驗大家成果的時候到了,
- 仔細想想上面七種特殊情況的產生原因。
- 思考下面這些值的比較結果。
[] == ![]; // ?
2 == [2]; // ?
'' == [null] // ?
Number.prototype.valueOf = function() {
return 3;
};
new Number( 2 ) == 3; // ?
複製程式碼