# The Difference between ==(相等)and ===(全等) ### “=” 一個等號很單純,就是指定、賦予值。 ` let a = 3;` 將等號右手邊的值指定到a變數中。 ### == vs === == 一般相等比較 Abstract Equality Comparison ("loose equality", "double equals") * 先強制轉型後比較 === 嚴格相等比較Strict Equality Comparison ("strict equality", "identity", "triple equals") * 不會強制轉型 ### type conversion (coercion) 強制轉型 分為兩種 1.「明確的」強制轉型(explicit coercion),有明確的刻意寫出轉換型別的動作。 例如: ToString、ToNumber、ToBoolean 等等。。 2.「隱含的」強制轉型(implicit coercion),沒有明確指出要轉換型別但卻轉型的動作。 ```javascript= var a = 42; var b = String(a); // 明確的強制轉型 var c = a + ''; // 隱含的強制轉型 b; // '42' c; // '42' ``` ### 「隱含的」強制轉型狀況? 1. “+” 運算子 當其中一方是字串時,+就是字串的串接運算子。會將另一方強制轉值為字串。 ```javascript= const a = '1'; const b = 1; const c = [1, 2]; const d = [3, 4]; a + 1; // "11" b + 1; // 2 b + ''; // "1" c + d; // "1,23,4" //陣列 c 和 d 分別會使用 toString 轉為 '1, 2' 與 '3, 4'。 ``` 2. 使用數學運算子將字串轉為數字(除了+號) ```javascript= const a = '1'; a + 1; // "11" a - 0; // 1 數字 a * 1; // 1 數字 a / 1; // 1 數字 ``` 3. 隱含的強制轉換為Boolean值 * 條件判斷(if/for/while) * 三元運算是 a=b?c:d * 邏輯運算子 || or && and ```javascript= var a = 12345; var b = 'Hello World'; var c; // undefined var d = null; if (a) { // true console.log('a 是真的'); // a 是真的 } while (c) { // false console.log("c "); } c = d ? a : b; console,log(c) //'Hello World' if ((a && b) || c) { // true console.log('結果是真的'); // 結果是真的 } ``` 補充:運算子 || 與 && ( 短路求值 short circuiting)更短更簡潔的判斷式 * OR operator || short circuiting 假如值是truthy value,他會直接回傳那個truthy value 假如都沒有truthy value,就會回傳比較中的最後一個值 ```javascript= console.log(3 || 'Jonas'); //3 console.log('' || 'Jonas');//Jonas console.log(true || 0);//true console.log(undefined || null|| 0); //0 console.log(undefined || 0 || '' || 'hello' || 23 || null); //hello ``` 實作:可以用來設定預設值 `const guest = name.firstName || name.secondName || 'anonymous'; ` * AND operator && short circuiting 它跟OR operator的作用相反。 假如值是falsy value,他會直接回傳那個falsy value 假如都沒有falsy value,就會回傳比較中的最後一個值 ```javascript= console.log(0 && 'jonas'); //0 console.log('' && 'jonas'); //'' console.log(7 && 'jonas'); //jonas console.log('hello' && 23 && null && 'jonas'); //null console.log('hello' && 23 && {} && 'jonas'); //'jonas' ``` * 補充:The Nullish Coalescing Operator 空合併運算子 幾乎跟OR operator一樣, 但只有null and undefined會被當成falsy value也就是Nullish value ```javascript= console.log(0 || 10) //10 console.log(0 ?? 10); //0 console.log(undefined ?? 10); //10 console.log(undefined ?? 10 ?? 'hello'); //10 console.log(undefined ??null?? '' ?? 0 ??'hello' ?? 23) // '' ``` ## 規則要注意的點: #### 如果型別相同,就會以同一性做比較,但要注意 * NaN 不等於任何值包括自己。不管是 == 或是 === * +0、-0 彼此相等。不管是 == 或是 === * 物件(object、array、function)的相等是比較參考(reference),若指向同一個參考才是相等。 ```javascript= var a = {weather : "sunny"}; var b; b = a; console.log(a) //sunny console.log(b) //sunny b === a //true ``` #### 如果型別不同,則會先將其中一個或兩個值先做強制轉型,再用型別相同的同一性做比較。 * 字串與數字做比較下,字串會透過Number()嘗試轉型為數字。 * 如果其中一個為布林值,會將true轉為1,false轉為0,布林值轉為數字。 * null 與 undefined 在寬鬆相等( == )下會強制轉型為彼此,因此是相等的,但不等於其他值。在嚴格相等比較( === )時undefined等於自己,null也只等於自己。 * 若比較的對象是物件,使用 valueOf()(優先)或 toString() 將物件取得基本型別的值,再做比較。 ## 結論 寬鬆相等(Loose Equals) vs 嚴格相等(Strict Equals) 關於相等性的運算子有四個 「 == 」(寬鬆相等性 loose equality)、 「 === 」(嚴格相等性 strict equality)、 「!=」(寬鬆不相等 loose not-equality)和 「 !== 」(嚴格不相等 strict not-equality)。 =="很多人會説 == 與 === 的差異在於 , === 會做型別檢查而 == 不會,這樣的說法不夠準確,要說 , == 與 === 的差異在於是否會做強制轉型, == 會做強制轉型,而 === 不會。"== 參考連結: [你懂 JavaScript 嗎?#8 強制轉型(Coercion)](https://cythilya.github.io/2018/10/15/coercion/) [js真值表](https://thomas-yang.me/projects/oh-my-dear-js/) [Web開發學習筆記02 — 等號比較運算子(Equality operators) “==” vs. “===”](https://teagan-hsu.coderbridge.io/2020/10/17/equality-operators/) ## 問答補充: #### 問題一: ```javascript= const a = '123'; const b = 123; a === b; // 答案是? a == b; // 答案是? ``` :::spoiler answer a === b; // false a == b; // true ::: #### 問題二: ```javascript= const a = true; const b = 123; a === b; // 答案是? a == b; // 答案是? ``` :::spoiler answer a === b; // false a == b; // false ::: #### 問題三: ```javascript= const a = null; const b = 123; a === b; // 答案是? a == b; // 答案是? ``` :::spoiler answer a === b; // false a == b; // false ::: #### 問題四: ```javascript= const a = '1,2,3'; const b = [1, 2, 3]; a === b; // 答案是? a == b; // 答案是? ``` :::spoiler answer a === b; // false a == b; // true ::: #### 問題五: ![](https://i.imgur.com/SKM6bZ3.jpg) :::spoiler answer 因為String轉換成Number,故0 == 0 0 == "0" //true 因為empty array(object type)轉為empty string(primitive type),故[]轉變成"",而""是String再轉換為Number,故""為0,最後0 == 0成立! 0 == [] //true 按照的解釋,[]轉為""(String),"0"與""皆為String,所以Javascript不會再強制轉換類型了,故"0" != [] "0" == [] //false ::: #### 終極問答: ```javascript= '0' == false; false == 0; false == ''; false == []; false == {}; '' == 0; '' == []; '' == {}; 0 == []; 0 == {}; [] == ![]; 2 == [2]; '' == [null]; 0 == '\n'; ``` :::spoiler answer "0" == false;,true,字串轉數字、布林再轉數字 false == 0;,true,布林轉數字 false == "";,true,字串轉數字、布林再轉數字 false == [];,true,布林轉數字、陣列取 toString 得到空字串再轉數字 false == {};, false,布林轉數字、物件取 valueOf 得到空物件 "" == 0;,true,字串轉數字 "" == [];,true,字串轉數字、陣列取 toString 得到空字串再轉數字 "" == {};,false,字串轉數字、物件取 valueOf 得到空物件 0 == [];,true,陣列取 toString 得到空字串再轉數字 0 == {};,false,物件取 valueOf 得到空物件 [] == ![],true,左手邊取 valueOf 得到空字串再轉數字得到 0,右手邊被 ! 強制轉為布林得到 false 再轉為數字 2 == [2],true,陣列取 toString 得到字串 ‘2’ 再轉數字 "" == [null],true,陣列取 toString 得到空字串,轉數字後得到 0 0 == '\n',true,’\n’ 意即 ‘ ‘(空白),轉數字後得到 0 :::