[] == ![] ?揭曉你不知道的 ==

語言: CN / TW / HK

theme: smartblue

我正在參加「掘金·啟航計劃」

前言

日常專案開發中,大部分的專案規範會提到使用===代替==,究其原因,無非是相對來講===的結果是 更可預測 的,相比之下==伴隨著隱式型別轉換。

兩者主要的區別就在於==用於檢查 是否相等,而===檢查的是 值與型別 是否相等。別小看這簡單的兩句話,其中伴隨的隱式轉換可不簡單。

舉個🌰: 1 == "1" 到底是 1 轉換成 "1" 還是 "1" 轉換成1呢?

知其所以然

思考🤔

求相等運算子的結果總是返回Boolean型別,反映運算子所命名的兩個運算元之間的關係是否成立。但,你真的知道 == 的工作原理嗎?試著看看以下程式碼的執行結果

js undefined == null; // true NaN == NaN; // false 1 == "1"; // true 1 == true; // true 2 == true; // false [] == [] // false "" == [] // true 0 == [] //true true == [] // false true == ![] // false true == !![] // true [] == ![] // true "a" == new String("a"); // true new String("a") == new String("a"); // false ... 如果你對上面的結果一知半解,或者知道結果但是不知道內部是如何轉換過來的,那麼請繼續往下看

同類型比較(🐕==🐶)

關於 a == b ;假設兩者型別相同

1、 那麼當 typeof aundefined,又或者兩者皆為null,結果為 true

js undeinfed == undefined // true null == null // true

2、 當typeof astring時,若a、b 是完全相同的字元序列,返回 true

js 'abc' == 'abc' // true

3、 當typeof anumber時,若 ab 存在1個及以上是 NaN 時,返回 false;否則如果數值相等則為 true,其餘情況為 false

js 123 == 123 // true NaN == NaN // false

4、 當typeof aboolean時,若a、b 都為 true 或都為 false 時,返回 true;否則返回 false

js true == true // true false == false // true false == true // false

5、 當typeof aobject時,若a、b 指向同一個物件,返回 true;若 a、b都為 null 返回 true,否則返回 falsejs {} == {} // false [] == [] // false,千萬不可使用 xxx == [] 來判斷陣列是否為空 new String("a") == new String("a"); // false let obj = {} let a = obj let b = obj a == b // true null == null

不同型別比較(🐖==🐕)(重點)

關於 a == b ;假設兩者型別不相同

1、ab 中有一個是undefined,另一個是null時,返回 true js undefined == null // true 2、ab 中有一個是number,一個是string,那麼會將string轉化為number再進行比較: js 1 == '1' // true,轉化成 1 == 1進行比較;'1' == 1 同理 3、 ab 當中存在 boolean時 ,將 boolean 轉為number 再進行比較: js 1 == true // true,轉化成 1 == 1進行比較; '1' == true // true 轉化成 '1' == 1 => 1 == 1 '2' == true // false '0' == false // true 4、ab 中有一個是object(非null),且另一個為基本資料型別 ,則先呼叫 object的valueOf方法,若結果為基本資料型別,則返回結果進行比較;否則呼叫object的toString方法,若結果為基本資料型別,則返回結果進行比較,否則丟擲錯誤

```js // 優先呼叫valueOf "a" == new String("a"); // true, new String('a').valueOf() === 'a'

let obj = { valueOf(){ return 2 } } 2 == obj // true

// valueOf沒有返回基本型別則呼叫toString let obj1 = { toString(){ return '3' } } 3 == obj1 // true

// toString沒有返回基本型別,報錯 let obj2 = { toString(){ return {} } } 3 == obj2 // 報錯 Cannot convert object to primitive value

0 == [] // true 轉化為 0 == '' => 0 == 0

5、**需要注意的是**,按照上述第四種情況,會出現一些令人意想不到的情況js true == [] // false,[] 被轉化成'' => 0 true == ![] // false, 轉化成 true == !true; true == !![] // true, 轉化成 true == !!true; // 同理 false == [] // true false == ![] // true false == !![] // false [] == ![] // true 本質上是[] == false; 轉換為 '' == false => 0 == 0 => true `` 這是因為在js中,引用資料型別轉化為boolean會被轉為true,因此[]加上!之後 會先將[]`轉為 true,再進行取反,結果就為 false

===👬

上面提到全等號檢查的是 值與型別,那麼當兩個值型別不同時結果直接為false,若是基本型別且型別相同時則根據自身值是否相同進行判斷。需要注意的是:NaN === NaN 結果是 false

若兩個值皆為 引用型別,則需要判斷兩者是否指向同一個物件,是則返回 true,否則為 false

總結

大部分情況下其實使用 == 都是相對安全的,很多情況下也能簡化我們的程式碼。 容易混淆的主要有以下幾種情況(這些情況下如果不夠明確,那麼考慮使用===,這對於後續其他開發者來講也是有利的): - 比較的值裡面有一邊可能是boolean型別(true/false) - 比較的值裡面有一邊可能是0''[]

更多時候,如果你能明確知道你寫的程式碼是你想要的結果以及明確其中是怎麼轉換的,那麼==號就是安全的!否則請儘量避免使用==,而是使用===

相信看到這裡的你已經對其中的轉換規則有了更加深入的理解!

寫得不對或不好的地方歡迎大家指正交流~~