Javascript 值的比較

2023-02-17 10:37 更新

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

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

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

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

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

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

所有比較運(yùn)算符均返回布爾值:

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

示例:

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

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

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

字符串比較

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

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

例如:

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

字符串的比較算法非常簡(jiǎn)單:

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

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

在第二個(gè)例子中,字符串 Glow 與 Glee 的比較則需要更多步驟,因?yàn)樾枰饌€(gè)字符進(jìn)行比較:

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

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

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

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

不同類型間的比較

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

例如:

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

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

例如:

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

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

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

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

例如:

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

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

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

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

嚴(yán)格相等

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

alert( 0 == false ); // true

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

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

這是因?yàn)樵诒容^不同類型的值時(shí),處于相等判斷符號(hào) == 兩側(cè)的值會(huì)先被轉(zhuǎn)化為數(shù)字。空字符串和 false 也是如此,轉(zhuǎn)化后它們都為數(shù)字 0。

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

嚴(yán)格相等運(yùn)算符 === 在進(jìn)行比較時(shí)不會(huì)做任何的類型轉(zhuǎn)換。

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

讓我們?cè)囋嚕?

alert( 0 === false ); // false,因?yàn)楸槐容^值的數(shù)據(jù)類型不同

同樣的,與“不相等”符號(hào) != 類似,“嚴(yán)格不相等”表示為 !==

嚴(yán)格相等的運(yùn)算符雖然寫起來(lái)稍微長(zhǎng)一些,但是它能夠很清楚地顯示代碼意圖,降低你犯錯(cuò)的可能性。

對(duì) null 和 undefined 進(jìn)行比較

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

當(dāng)使用嚴(yán)格相等 === 比較二者時(shí)

它們不相等,因?yàn)樗鼈儗儆诓煌念愋汀?

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

當(dāng)使用非嚴(yán)格相等 == 比較二者時(shí)

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

alert( null == undefined ); // true

當(dāng)使用數(shù)學(xué)式或其他比較方法 < > <= >= 時(shí):

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

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

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

通過(guò)比較 null 和 0 可得:

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

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

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

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

特立獨(dú)行的 undefined

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

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

為何它看起來(lái)如此厭惡 0?返回值都是 false!

原因如下:

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

避免問(wèn)題

我們?yōu)楹我芯可鲜鍪纠课覀冃枰獣r(shí)刻記得這些古怪的規(guī)則嗎?不,其實(shí)不需要。雖然隨著代碼寫得越來(lái)越多,我們對(duì)這些規(guī)則也都會(huì)爛熟于胸,但是我們需要更為可靠的方法來(lái)避免潛在的問(wèn)題:

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

總結(jié)

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

任務(wù)


值的比較

重要程度: 5

以下表達(dá)式的執(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. 嚴(yán)格相等模式下,類型不同得 false。
  6. 與第 4 題同理,?null ?只與 ?undefined ?相等。
  7. 不同類型嚴(yán)格不相等。


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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)