前言
來談談 JavaScript 的比較運算子,之前我們紀錄的所有東西,單獨來看可能不知道可以被實際運用在哪裡,直到把運算子的「優先性」、「相依性」、「強制型轉」這三種東西兜再一起,這就是本篇文章要記錄的東西。
優先性、相依性、強制型轉
當我們把「優先性」、「相依性」、「強制型轉」這三種東西兜再一起時,就會發生一些 JavaScript 看似奇怪,但實際上非常合理的事情,但是不用擔心,因為這些東西我們都學過了。
直接看例子:
1 | console.log(1 < 2 < 3); // true |
合理嗎?
常識判斷「 1 小於 2 小於 3 」,正確!
那如果是這樣呢?
1 | console.log(3 < 2 < 1); // true |
看到這,是不是會懷疑是不是有BUG?
為什麼「3 小於 2 小於 1」是正確的?
讓我們用科學的方式來解釋它
記得「運算子的優先性」與「運算子的相依性」嗎?
讓我們查一下表格
在這個例子中,有兩個「<」代表優先性是一樣的,而「<」的相依性為「左相依」,代表最左邊的會先執行。
於是,實際過程中是這樣的:
1 | //實際上會先執行以下判斷 |
3 並不小於 2 因此回傳了 false
,接著原先的例子就會變成這樣
1 | console.log(false < 1); // true |
接著我們可能會感到更奇怪了,布林 false 如何與數值 1 比較?
這並不是預期中的型別,但仍然可以進行比較,這是因為 JavaScript 中的「強制型轉」。
「強制型轉」把布林
false
轉換成了什麼數值?
可以運用以下方法觀察
1 | Number(false); // 0 |
看到了嗎,JavaScript 把 false
強制轉型成為數值 0 ,讓比較繼續進行
1 | console.log(0 < 1); // true |
因此最後輸出的結果才會是「true
」
懶人包:因為函式運算子執行的順序以及值的強制型轉影響
當然,也可以回頭想想文章一開始提到的例子,雖然結果與我們所想的相同,但實際上底層的運作跟我們想的並不一樣哦~
「強制型轉」的缺點
強制型轉雖然很便利,但上面的例子可以看出也有缺點,不是每個強制轉型後的情況都是可以預期的,我們先用剛剛的觀察方法觀察一些強制型轉後的變化。
1 | Number('3'); // 3 |
NaN (Not a Number)
表示不是數字 ,NaN 代表有個東西想轉換成數值型別,但它不是數值,所以無法轉換。以本例來說 undefined 不能轉成數值。
但是,null 經過強制型轉後得到的答案是 0 ? 有符合我們的預期嗎?
我們可以透過觀察得知,並不是每次轉型結果都很明顯,這會導致相當多難以預期的 BUG。
強制轉型雖然很便利,但同時也很危險。
既然這樣不使用不就好了? 或者先檢查兩個東西是否相等?
的確可以這樣做,讓我們看看 JavaScript 運算子優先性表格。
使用「==」進行比較
好的,我們找到了程式語言相當常見的雙等號「==」,代表「檢查兩個東西是否相等」,讓我們直接來點例子:
1 | console.log(3 == 3); // true |
在我們知道強制轉型的概念後,大部分的例子都可以了解為什麼,但是我們剛剛不是才觀察過 null
可以被強制轉型成數值 0 嗎,怎麼在這邊是 false
呢?
有很多特殊情況並不如我們所想的那樣,來個延伸例子
1 | console.log(null < 1); // true |
雖然 null
會轉型為 0 ,但在某種情況下,像是在「比較」的時候並不會轉型為 0,困惑嗎?
沒錯,這造成了很多疑惑和問題。
然而我們也透過上述其他例子得知,使用「==」進行比較時,會進行強制型轉。也因為強制型轉的關係,會使得結果可能不如我們預期。這其實也被視為這個語言的缺點。
是不是開始覺得混亂了。 我也是,幸好這問題有解!
使用「===」進行嚴格比較
用三個等號比較兩個東西,就不會進行強制型轉。
使用三等號驗證剛剛使用雙等號比較的例子
1 | console.log(3 === 3); // true |
如果兩個值不是同個型別,就會回傳 false
。此時的 JavaScript 不會進行強制型轉。
使用三等號來比較值的話,可以避免ㄧ些奇怪的潛在錯誤。在絕大多數 99.9% 的情形,我們都應該使用三個等號來比較相等性,除非你是「故意」要使用雙等號。
然而還有很多關於雙等號、三等號的比較,可以到這裡來查看。