2021 年 10 月 1 日

比較

我們從數學中了解到許多比較運算子。

在 JavaScript 中,它們的寫法如下

  • 大於/小於:a > ba < b
  • 大於/小於或等於:a >= ba <= 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

比較兩個字串的演算法很簡單

  1. 比較兩個字串的第一個字元。
  2. 如果第一個字串的第一個字元大於(或小於)另一個字串,則第一個字串大於(或小於)第二個字串。我們完成了。
  3. 否則,如果兩個字串的第一個字元相同,則以相同的方式比較第二個字元。
  4. 重複這個步驟,直到任何一個字串結束。
  5. 如果兩個字串在相同長度處結束,則它們相等。否則,較長的字串較大。

在上面第一個範例中,比較 'Z' > 'A' 在第一步就得到結果。

第二個比較 'Glow''Glee' 需要更多步驟,因為字串是逐字元比較

  1. GG 相同。
  2. ll 相同。
  3. o 大於 e。在此停止。第一個字串較大。
不是真正的字典,而是 Unicode 順序

上面提供的比較演算法大致等同於字典或電話簿中使用的演算法,但它並不完全相同。

例如,大小寫很重要。大寫字母 "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 轉換會使用另一組規則。

嚴格相等

常規相等檢查 == 有個問題。它無法區分 0false

alert( 0 == false ); // true

空字串也發生同樣的事情

alert( '' == false ); // true

這是因為相等運算子 == 會將不同類型的運算元轉換為數字。空字串就像 false 一樣,會變成零。

如果我們想區分 0false 該怎麼辦?

嚴格相等運算子 === 在不進行類型轉換的情況下檢查相等性。

換句話說,如果 ab 是不同類型的,則 a === b 會立即傳回 false,而不會嘗試將它們轉換。

我們來試試看

alert( 0 === false ); // false, because the types are different

還有一個「嚴格不相等」運算子 !== 類似於 !=

嚴格相等運算子寫起來有點長,但可以清楚地說明正在發生的事情,並且減少錯誤的空間。

與 null 和 undefined 比較

nullundefined 與其他值比較時,會出現不直觀的行為。

對於嚴格相等檢查 ===

這些值不同,因為它們各自是不同的類型。

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 為假。

另一方面,undefinednull 的等式檢查 == 定義為在沒有任何轉換的情況下,它們彼此相等,且不與其他任何東西相等。這就是為什麼 (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 僅等於 nullundefined,以及沒有其他值。

避免問題

我們為什麼要探討這些範例?我們應該隨時記住這些特殊情況嗎?嗯,其實不用。事實上,這些棘手的東西會隨著時間逐漸變得熟悉,但有一個可靠的方法可以避免它們造成的問題

  • 除了嚴格等式 === 之外,請特別小心任何與 undefined/null 的比較。
  • 不要對可能為 null/undefined 的變數使用比較 >= > < <=,除非你真的確定自己在做什麼。如果變數可以有這些值,請分別檢查它們。

摘要

  • 比較運算子會傳回布林值。
  • 字串會按照「字典」順序逐個字母進行比較。
  • 當不同類型的值進行比較時,它們會轉換為數字(排除嚴格等式檢查)。
  • nullundefined 值彼此相等 ==,且不與任何其他值相等。
  • 使用 >< 等比較時,請小心處理偶爾可能是 null/undefined 的變數。建議分別檢查 null/undefined

任務

重要性:5

這些表達式的結果是什麼?

5 > 4
"apple" > "pineapple"
"2" > "12"
undefined == null
undefined === null
null == "\n0\n"
null === +"\n0\n"
5 > 4 → true
"apple" > "pineapple" → false
"2" > "12" → true
undefined == null → true
undefined === null → false
null == "\n0\n" → false
null === +"\n0\n" → false

一些原因

  1. 顯然為真。
  2. 字典比較,因此為假。"a" 小於 "p"
  3. 再次進行字典比較,第一個字元 "2" 大於第一個字元 "1"
  4. nullundefined 僅彼此相等。
  5. 嚴格相等是嚴格的。兩邊的類型不同會導致 false。
  6. 類似於 (4)null 僅等於 undefined
  7. 不同類型的嚴格相等。
教學課程地圖

留言

留言前請先閱讀此內容…
  • 如果您有改善建議,請 提交 GitHub 議題 或發起拉取請求,而非留言。
  • 如果您無法理解文章中的內容,請詳細說明。
  • 若要插入少數幾個字的程式碼,請使用 <code> 標籤,若要插入多行程式碼,請將其包覆在 <pre> 標籤中,若要插入超過 10 行的程式碼,請使用沙盒 (plnkrjsbincodepen…)