我們從數學中了解到許多比較運算子。
在 JavaScript 中,它們的寫法如下
- 大於/小於:
a > b
、a < b
。 - 大於/小於或等於:
a >= b
、a <= b
。 - 等於:
a == b
,請注意,雙等號==
表示等於測試,而單等號a = b
表示賦值。 - 不等於:在數學中,符號為
≠
,但在 JavaScript 中,寫作a != b
。
在本文中,我們將進一步了解不同類型的比較,以及 JavaScript 如何執行這些比較,包括重要的特殊性。
在最後,你會找到一個避免「JavaScript 怪癖」相關問題的好食譜。
布林值是結果
所有比較運算子都會傳回布林值
true
– 表示「是」、「正確」或「真」。false
– 表示「否」、「錯誤」或「假」。
例如
alert( 2 > 1 ); // true (correct)
alert( 2 == 1 ); // false (wrong)
alert( 2 != 1 ); // true (correct)
比較結果可以指定給變數,就像任何值一樣
let result = 5 > 4; // assign the result of the comparison
alert( result ); // true
字串比較
為了查看一個字串是否大於另一個字串,JavaScript 使用所謂的「字典」或「字彙」順序。
換句話說,字串會逐字元比較。
例如
alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true
比較兩個字串的演算法很簡單
- 比較兩個字串的第一個字元。
- 如果第一個字串的第一個字元大於(或小於)另一個字串,則第一個字串大於(或小於)第二個字串。我們完成了。
- 否則,如果兩個字串的第一個字元相同,則以相同的方式比較第二個字元。
- 重複這個步驟,直到任何一個字串結束。
- 如果兩個字串在相同長度處結束,則它們相等。否則,較長的字串較大。
在上面第一個範例中,比較 'Z' > 'A'
在第一步就得到結果。
第二個比較 'Glow'
和 'Glee'
需要更多步驟,因為字串是逐字元比較
G
和G
相同。l
和l
相同。o
大於e
。在此停止。第一個字串較大。
上面提供的比較演算法大致等同於字典或電話簿中使用的演算法,但它並不完全相同。
例如,大小寫很重要。大寫字母 "A"
不等於小寫字母 "a"
。哪一個較大?小寫字母 "a"
。為什麼?因為小寫字元在 JavaScript 使用的內部編碼表(Unicode)中具有較大的索引。我們將在章節 字串 中回顧此處的具體詳細資訊和後果。
不同類型的比較
在比較不同類型的值時,JavaScript 會將這些值轉換為數字。
例如
alert( '2' > 1 ); // true, string '2' becomes a number 2
alert( '01' == 1 ); // true, string '01' becomes a number 1
對於布林值,true
會變成 1
,而 false
會變成 0
。
例如
alert( true == 1 ); // true
alert( false == 0 ); // true
以下情況同時發生是可能的
- 兩個值相等。
- 其中一個值作為布林值為
true
,而另一個值作為布林值為false
。
例如
let a = 0;
alert( Boolean(a) ); // false
let b = "0";
alert( Boolean(b) ); // true
alert(a == b); // true!
從 JavaScript 的觀點來看,這個結果很正常。等式檢查會使用數字轉換來轉換值(因此 "0"
會變成 0
),而明確的 Boolean
轉換會使用另一組規則。
嚴格相等
常規相等檢查 ==
有個問題。它無法區分 0
和 false
alert( 0 == false ); // true
空字串也發生同樣的事情
alert( '' == false ); // true
這是因為相等運算子 ==
會將不同類型的運算元轉換為數字。空字串就像 false
一樣,會變成零。
如果我們想區分 0
和 false
該怎麼辦?
嚴格相等運算子 ===
在不進行類型轉換的情況下檢查相等性。
換句話說,如果 a
和 b
是不同類型的,則 a === b
會立即傳回 false
,而不會嘗試將它們轉換。
我們來試試看
alert( 0 === false ); // false, because the types are different
還有一個「嚴格不相等」運算子 !==
類似於 !=
。
嚴格相等運算子寫起來有點長,但可以清楚地說明正在發生的事情,並且減少錯誤的空間。
與 null 和 undefined 比較
當 null
或 undefined
與其他值比較時,會出現不直觀的行為。
- 對於嚴格相等檢查
===
-
這些值不同,因為它們各自是不同的類型。
alert( null === undefined ); // false
- 對於非嚴格檢查
==
-
有一個特殊規則。這兩個是一個「甜蜜伴侶」:它們彼此相等(在
==
的意義上),但與任何其他值都不相等。alert( null == undefined ); // true
- 對於數學和其他比較
< > <= >=
-
null/undefined
會轉換為數字:null
變成0
,而undefined
變成NaN
。
現在讓我們看看應用這些規則時會發生一些有趣的事情。更重要的是,如何避免陷入它們的陷阱。
奇怪的結果:null 與 0
我們來比較 null
和 0
alert( null > 0 ); // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true
在數學上,這很奇怪。最後一個結果表明「null
大於或等於零」,因此在上面的其中一個比較中它必須為 true
,但它們都是 false。
原因在於等式檢查 ==
和比較 > < >= <=
的運作方式不同。比較會將 null
轉換為數字,並將其視為 0
。這就是為什麼 (3) null >= 0
為真,而 (1) null > 0
為假。
另一方面,undefined
和 null
的等式檢查 ==
定義為在沒有任何轉換的情況下,它們彼此相等,且不與其他任何東西相等。這就是為什麼 (2) null == 0
為假。
無法比較的 undefined
不應將 undefined
值與其他值進行比較
alert( undefined > 0 ); // false (1)
alert( undefined < 0 ); // false (2)
alert( undefined == 0 ); // false (3)
它為什麼這麼討厭零?總是為假!
我們會得到這些結果,因為
- 比較 (1) 和 (2) 會傳回
false
,因為undefined
會轉換為NaN
,而NaN
是特殊數字值,會針對所有比較傳回false
。 - 等式檢查 (3) 會傳回
false
,因為undefined
僅等於null
、undefined
,以及沒有其他值。
避免問題
我們為什麼要探討這些範例?我們應該隨時記住這些特殊情況嗎?嗯,其實不用。事實上,這些棘手的東西會隨著時間逐漸變得熟悉,但有一個可靠的方法可以避免它們造成的問題
- 除了嚴格等式
===
之外,請特別小心任何與undefined/null
的比較。 - 不要對可能為
null/undefined
的變數使用比較>= > < <=
,除非你真的確定自己在做什麼。如果變數可以有這些值,請分別檢查它們。
摘要
- 比較運算子會傳回布林值。
- 字串會按照「字典」順序逐個字母進行比較。
- 當不同類型的值進行比較時,它們會轉換為數字(排除嚴格等式檢查)。
null
和undefined
值彼此相等==
,且不與任何其他值相等。- 使用
>
或<
等比較時,請小心處理偶爾可能是null/undefined
的變數。建議分別檢查null/undefined
。
留言
<code>
標籤,若要插入多行程式碼,請將其包覆在<pre>
標籤中,若要插入超過 10 行的程式碼,請使用沙盒 (plnkr、jsbin、codepen…)