前言
直接講結論:「不管什麼時候,都應該只使用三個等於來進行比較,除非是進行教學或者是-故意的。」
「==」和「===」的差異
使用「==」進行比較
首先我們必須了解「==」實際上在做什麼,這部分的觀念其實在[JavaScriptWeird]No.16 強制型轉、[JavaScriptWeird]No.17 比較運算子都有提到一些。
使用「==」進行比較時,「==」會嘗試將左右兩邊的型別根據某個規則,嘗試將型別轉成一致並進行比較,最後回傳比較結果。
1 | var a = 1; |
使用「===」進行比較
如果使用「===」進行比較,就不會觸發型別轉換,因此結果會比較接近我們預期的那樣。
1 | var a = 1; |
「==」和「===」的比較表
可以上 JS Comparison Table 查詢各種比較結果。
為什麼我們應該只使用「===」比較
因為使用「==」會觸發型別轉換,而且透過雙等號比較表可以得知其中規則相當複雜,可能會跑出一些非預期的結果。
而使用「===」的話,因為不會觸發型別轉換,較容易預測結果,而且比較表也相對好記憶。
原始型別與物件型別的差異
之前提到一些原始型別 (Primitive Types) 與物件型別 (Object Types) 的差異,這邊將提到另外一個差異:
- 與原始型別不同,物件型別是比較記憶體位址
1
2
3var obj = { number: 1 }
var obj2 = obj;
console.log(obj === obj2); // true
眼尖的你應該會發現,比較表上明明寫著兩個物件相比都是 false ,那麼為什麼這邊會是 true 呢?
我們可以把這段 code 在記憶體的樣子畫出來:
可以發現變數 obj
與 obj2
都是指向同一個記憶體位址,因此第三行的比較其實是「比較兩個變數指向的記憶體位址」,既然兩個變數都指向同一個記憶體位址,那麼答案自然會是 true 。
同理,修改一下例子,並畫圖了解:
1 | var obj = { number: 1 } |
由前一個例子可知,物件型別之間的比較比的是記憶體的位址,從這張圖看來,兩個 {} 物件在記憶體中的位置並不相同,所以比較的結果才會是 false。
這樣就可驗證為什麼只要是物件型別之間的比較都會是 false 了,因為只要產生一個新物件,就會是不同的記憶體位址。
而有哪些是物件型別呢?
只要不屬於原始型別的那六種,都是物件型別。這倒是可以用很簡單的二分法來判斷。
特殊的例子
NaN (Not a Number)
顧名思義 NaN 就是非數字(Not a Number),但是很弔詭的是:
使用
typeof NaN
得到的結果會是數字型別 (number)1
console.log(typeof NaN); // number
而 NaN 本身也無法使用「===」或「==」與自己比較
1
console.log(NaN === NaN); // false
神奇的是如果你拿數字型別跟 NaN 相比也會是 false
1
console.log(typeof(1) === NaN); // false
NaN 如何產生的
相當容易產生,只要 Javascript 發生自動型轉或者我們主動將值轉換成數字時,當中混有無法轉成數值的東西時,就會產生 NaN。
因此 NaN 是個相當可怕的東西,我們應該避免產生 NaN。
使用 isNaN() 檢查是否為 NaN
因為我們沒辦法從上面任何方式判斷是否為 NaN ,但是幸好還有 isNaN() 可以使用,使用方法相當容易:
1 | var test = 1 + 's'; |
這樣子就能判斷是否為 NaN 了,另外這是 MDN 對於 NaN 的解釋
不支援 isNaN() 的瀏覽器的因應措施
很不幸的 isNaN()
好像不是所有瀏覽器都支援,但是我們可以透過 polyfill 令不支援 isNaN()
的瀏覽器也可以使用。
而幸運的是,這可以在 MDN 上找到。
感恩 MDN 讚嘆 MDN
心得
這是上完保哥課程後的第一篇記錄文,很高興能用到課堂上的知識來加深這些觀念的印象,而最棒的是我看的這支影片居然也用同樣的方式來介紹這些觀念,果然是高手所見略同呢。
我覺得對初心者來說,比起生硬的文字,最容易有印象的果然還是畫圖。
而且是必須要親自畫,不能只有看。而從「讀出程式碼」到畫出來的過程中,也可以了解自己觀念理解的正不正確,因為只要唸出來的是錯的,代表你想的也是錯的,自然畫出來的圖也會是錯的,這時候就會產生BUG。