Javascript 值的比較

2023-02-17 10:37 更新

我們知道,在數(shù)學中有很多用于比較大小的運算符。

在 JavaScript 中,它們的編寫方式如下:

  • 大于 / 小于:?a > b?,?a < b?。
  • 大于等于 / 小于等于:?a >= b?,?a <= b?。
  • 檢查兩個值的相等:?a == b?,請注意雙等號 ?==? 表示相等性檢查,而單等號 ?a = b? 表示賦值。
  • 檢查兩個值不相等:不相等在數(shù)學中的符號是 ??,但在 JavaScript 中寫成 ?a != b?。

在本文中,我們將進一步了解不同類型的比較,JavaScript 是如何進行比較的,包括一些重要的特殊性。

在文末給出了一些秘訣,幫助你避免 “JavaScript 陷阱”相關(guān)的問題。

比較結(jié)果為 Boolean 類型

所有比較運算符均返回布爾值:

  • ?true ?—— 表示“yes(是)”,“correct(正確)”或“the truth(真)”。
  • ?false ?—— 表示“no(否)”,“wrong(錯誤)”或“not the truth(非真)”。

示例:

alert( 2 > 1 );  // true(正確)
alert( 2 == 1 ); // false(錯誤)
alert( 2 != 1 ); // true(正確)

和其他類型的值一樣,比較的結(jié)果可以被賦值給任意變量:

let result = 5 > 4; // 把比較的結(jié)果賦值給 result
alert( result ); // true

字符串比較

在比較字符串的大小時,JavaScript 會使用“字典(dictionary)”或“詞典(lexicographical)”順序進行判定。

換言之,字符串是按字符(母)逐個進行比較的。

例如:

alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true

字符串的比較算法非常簡單:

  1. 首先比較兩個字符串的首位字符大小。
  2. 如果一方字符較大(或較?。瑒t該字符串大于(或小于)另一個字符串。算法結(jié)束。
  3. 否則,如果兩個字符串的首位字符相等,則繼續(xù)取出兩個字符串各自的后一位字符進行比較。
  4. 重復上述步驟進行比較,直到比較完成某字符串的所有字符為止。
  5. 如果兩個字符串的字符同時用完,那么則判定它們相等,否則未結(jié)束(還有未比較的字符)的字符串更大。

在上面的第一個例子中,'Z' > 'A' 比較在算法的第 1 步就得到了結(jié)果。

在第二個例子中,字符串 Glow 與 Glee 的比較則需要更多步驟,因為需要逐個字符進行比較:

  1. ??和 ?G? 相等。
  2. ?l? 和 ?l? 相等。
  3. ?o? 比 ?e? 大,算法停止,第一個字符串大于第二個。

非真正的字典順序,而是 Unicode 編碼順序

在上面的算法中,比較大小的邏輯與字典或電話簿中的排序很像,但也不完全相同。

比如說,字符串比較對字母大小寫是敏感的。大寫的 "A" 并不等于小寫的 "a"。哪一個更大呢?實際上小寫的 "a" 更大。這是因為在 JavaScript 使用的內(nèi)部編碼表中(Unicode),小寫字母的字符索引值更大。我們會在 字符串 這章討論更多關(guān)于字符串的細節(jié)。

不同類型間的比較

當對不同類型的值進行比較時,JavaScript 會首先將其轉(zhuǎn)化為數(shù)字(number)再判定大小。

例如:

alert( '2' > 1 ); // true,字符串 '2' 會被轉(zhuǎn)化為數(shù)字 2
alert( '01' == 1 ); // true,字符串 '01' 會被轉(zhuǎn)化為數(shù)字 1

對于布爾類型值,true 會被轉(zhuǎn)化為 1、false 轉(zhuǎn)化為 0。

例如:

alert( true == 1 ); // true
alert( false == 0 ); // true

一個有趣的現(xiàn)象

有時候,以下兩種情況會同時發(fā)生:

  • 若直接比較兩個值,其結(jié)果是相等的。
  • 若把兩個值轉(zhuǎn)為布爾值,它們可能得出完全相反的結(jié)果,即一個是 ?true?,一個是 ?false?。

例如:

let a = 0;
alert( Boolean(a) ); // false

let b = "0";
alert( Boolean(b) ); // true

alert(a == b); // true!

對于 JavaScript 而言,這種現(xiàn)象其實挺正常的。因為 JavaScript 會把待比較的值轉(zhuǎn)化為數(shù)字后再做比較(因此 "0" 變成了 0)。若只是將一個變量轉(zhuǎn)化為 Boolean 值,則會使用其他的類型轉(zhuǎn)換規(guī)則。

嚴格相等

普通的相等性檢查 == 存在一個問題,它不能區(qū)分出 0 和 false

alert( 0 == false ); // true

也同樣無法區(qū)分空字符串和 false

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

這是因為在比較不同類型的值時,處于相等判斷符號 == 兩側(cè)的值會先被轉(zhuǎn)化為數(shù)字。空字符串和 false 也是如此,轉(zhuǎn)化后它們都為數(shù)字 0。

如果我們需要區(qū)分 0 和 false,該怎么辦?

嚴格相等運算符 === 在進行比較時不會做任何的類型轉(zhuǎn)換。

換句話說,如果 a 和 b 屬于不同的數(shù)據(jù)類型,那么 a === b 不會做任何的類型轉(zhuǎn)換而立刻返回 false

讓我們試試:

alert( 0 === false ); // false,因為被比較值的數(shù)據(jù)類型不同

同樣的,與“不相等”符號 != 類似,“嚴格不相等”表示為 !==。

嚴格相等的運算符雖然寫起來稍微長一些,但是它能夠很清楚地顯示代碼意圖,降低你犯錯的可能性。

對 null 和 undefined 進行比較

當使用 null 或 undefined 與其他值進行比較時,其返回結(jié)果常常出乎你的意料。

當使用嚴格相等 === 比較二者時

它們不相等,因為它們屬于不同的類型。

alert( null === undefined ); // false

當使用非嚴格相等 == 比較二者時

JavaScript 存在一個特殊的規(guī)則,會判定它們相等。它們倆就像“一對戀人”,僅僅等于對方而不等于其他任何的值(只在非嚴格相等下成立)。

alert( null == undefined ); // true

當使用數(shù)學式或其他比較方法 < > <= >= 時:

null/undefined 會被轉(zhuǎn)化為數(shù)字:null 被轉(zhuǎn)化為 0,undefined 被轉(zhuǎn)化為 NaN

下面讓我們看看,這些規(guī)則會帶來什么有趣的現(xiàn)象。同時更重要的是,我們需要從中學會如何遠離這些特性帶來的“陷阱”。

奇怪的結(jié)果:null vs 0

通過比較 null 和 0 可得:

alert( null > 0 );  // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true

是的,上面的結(jié)果完全打破了你對數(shù)學的認識。在最后一行代碼顯示“null 大于等于 0”的情況下,前兩行代碼中一定會有一個是正確的,然而事實表明它們的結(jié)果都是 false。

為什么會出現(xiàn)這種反常結(jié)果,這是因為相等性檢查 == 和普通比較符 > < >= <= 的代碼邏輯是相互獨立的。進行值的比較時,null 會被轉(zhuǎn)化為數(shù)字,因此它被轉(zhuǎn)化為了 0。這就是為什么(3)中 null >= 0 返回值是 true,(1)中 null > 0 返回值是 false。

另一方面,undefined 和 null 在相等性檢查 == 中不會進行任何的類型轉(zhuǎn)換,它們有自己獨立的比較規(guī)則,所以除了它們之間互等外,不會等于任何其他的值。這就解釋了為什么(2)中 null == 0 會返回 false。

特立獨行的 undefined

undefined 不應(yīng)該被與其他值進行比較:

alert( undefined > 0 ); // false (1)
alert( undefined < 0 ); // false (2)
alert( undefined == 0 ); // false (3)

為何它看起來如此厭惡 0?返回值都是 false!

原因如下:

  • ?(1)? 和 ?(2)? 都返回 ?false ?是因為 ?undefined ?在比較中被轉(zhuǎn)換為了 ?NaN?,而 ?NaN ?是一個特殊的數(shù)值型值,它與任何值進行比較都會返回 ?false?。
  • ?(3)? 返回 ?false ?是因為這是一個相等性檢查,而 ?undefined ?只與 ?null ?相等,不會與其他值相等。

避免問題

我們?yōu)楹我芯可鲜鍪纠??我們需要時刻記得這些古怪的規(guī)則嗎?不,其實不需要。雖然隨著代碼寫得越來越多,我們對這些規(guī)則也都會爛熟于胸,但是我們需要更為可靠的方法來避免潛在的問題:

  • 除了嚴格相等 ?===? 外,其他但凡是有 ?undefined/null? 參與的比較,我們都需要格外小心。
  • 除非你非常清楚自己在做什么,否則永遠不要使用 ?>= > < <=? 去比較一個可能為 ?null/undefined? 的變量。對于取值可能是 ?null/undefined? 的變量,請按需要分別檢查它的取值情況。

總結(jié)

  • 比較運算符始終返回布爾值。
  • 字符串的比較,會按照“詞典”順序逐字符地比較大小。
  • 當對不同類型的值進行比較時,它們會先被轉(zhuǎn)化為數(shù)字(不包括嚴格相等檢查)再進行比較。
  • 在非嚴格相等 ?==? 下,?null ?和 ?undefined ?相等且各自不等于任何其他的值。
  • 在使用 ?>? 或 ?<? 進行比較時,需要注意變量可能為 ?null/undefined? 的情況。比較好的方法是單獨檢查變量是否等于 ?null/undefined?。

任務(wù)


值的比較

重要程度: 5

以下表達式的執(zhí)行結(jié)果是?

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

結(jié)果的原因:

  1. 數(shù)字間比較大小,顯然得 true。
  2. 按詞典順序比較,得 false。?"a"? 比 ?"p"? 小。
  3. 與第 2 題同理,首位字符 ?"2"? 大于 ?"1"?。
  4. ?null ?只與 ?undefined ?互等。
  5. 嚴格相等模式下,類型不同得 false。
  6. 與第 4 題同理,?null ?只與 ?undefined ?相等。
  7. 不同類型嚴格不相等。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號