[JS] ==、=== 和 Object.is()
JavaScript 的相等比較:
==、===和Object.is()
在 JavaScript 中想判斷變數或對象是否相等有以下三種方法:
- 一般相等(==)
- 嚴格相等(===)
- Object.is() 方法
前兩個比較運算子 == 和 === 都可以拿來判斷比較對象是否相等,不過兩者的差別究竟在哪裡?又為什麼要這樣設計?是我一開始學習 JavaScript 感到有點混淆的地方,也是滿常見的面試考題。
== 與 === 的差別
「大部分情況下不建議使用 ==,應該使用 ===」
初學 JavaScript 時常常會直接看到這樣的結論。簡單來說 == 不會進行型別檢查只會比較值,=== 則會同時檢查型別與值。
console.log('1' == 1); // true
console.log('1' === 1); // false
== 等於(Equal) 與 != 不等於
==等於(Equal)也稱作「鬆散/寬鬆相等(Loose Equal)」(相較於「嚴格相等」來說)- 由於 JavaScript 是個動態型別語言,因此可以允許不同型別的值做比較
==也具有「對稱性(symmetric)」,A == B的意思與B == A是相同的- 遇到不同型別的運算元時,會先自動轉型(type conversion)再比較內容
console.log('1' == 1); //true
console.log(true == 1); // true
不必管型別就能使用乍看之下很方便,但可以看看這幾個 tricky 的例子:
console.log(-0 == +0);
console.log(null == undefined);
console.log([1, 2] == '1,2');
console.log([] == false);
console.log([0] == false);
console.log('\n' == false);
console.log('0XA19' == 2585);
// 以上的結果都是 true
這是因為不同型別的值經過 JavaScript 的隱式轉型(Implicit Type Coercion) ,反而可能會有預期之外的結果。
這也是為什麼通常來說更建議使用 ===。
以下來做個簡單的分類:
同型別之間的比較
如果 Type(x) 與 Type(y) 相同,執行的結果就跟使用嚴格相等 x === y 一樣。
- String: 兩個 string 每一個字元跟順序都相同時才是 true
- Number: 兩個 number 的值相同時才是 true
+0與-0在==被視為相等、在===視為不相等- 只要任一運算元是
NaN就是 false;NaN不等於任何值(包含自己)
- Boolean: 運算元都是 true 或都是 false 時才是 true
- BigInt:兩個 BigInt 都有相同的值時才是 true
- Symbol: 兩個 symbol 都引用相同的 symbol 值 時才是 true
- Object: 兩個 object 都指向相同的位置時才是 true
JavaScript 的比較也會因為是不是原始型別(primitive type) 而有所差異。 非原始型別(像是 object、array 或 class)比較的基準會是看他們是否指向同一個參考(reference),而不是比較他們的值(value)。
let obj1 = { name: 'John' };
let obj2 = { name: 'John' };
let array1 = [1, 2, 3];
let array2 = [1, 2, 3];
console.log(obj1 == obj2); // false
console.log(array1 == array2); // false
這部分在下方 Reference vs Value 會有進一步的說明。
string 或 boolean 會轉為 number
string 或 boolean 被拿來跟 number 比較時,會先透過 Number() 轉為 number,再跟另一個 number 比較。
string 與 number 比較
console.log('' == 0); // true
console.log(' ' == 0); // true
console.log('' == ' '); // false
""被自動轉型成 0,因此"" == 0可以看作是0 == 0,兩值相等所以回傳 true" "即使包含了空白字元,但經過Number(" ")自動轉型仍是 0 ,因此也會回傳 true""與" "兩者型別相同(都是 string) 因此不需要轉型、直接比較內容,內容並不相等所以回傳 false。
boolean 與 number 比較
console.log(true == 1); // true
console.log(false == 0); // true
- true 被
Number(true)轉成 1 - false 被
Number(false)轉成 0
string 與 boolean 比較
string 與 boolean 都會先轉為 number 再作比較。
console.log('0' == false); // true
'0'字串透過Number('0')轉為數字 0false布林值透過Number(false)轉為數字 0'0' == false經過轉型後變成0 == 0,兩值相同回傳 true
console.log('true' == true); // false
'true'字串透過Number('true')因為無法轉型成數字因此結果是NaNtrue布林值透過Number(true)轉為數字 1'true' == true經過轉型後變成NaN == 1--> 只要出現 NaN 就回傳 false
null、undefined 的比較
運算元是 null 或 undefined 時的規則如下:
當其中一個運算元是 null 或 undefined,另一個運算元也必須是 null 或 undefined 才會回傳 true,否則一律回傳 false。
console.log(null == undefined); // true
console.log(null == 0); // false
console.log(undefined == 0); // false