JavaScript 比較運算符

2023-03-20 15:57 更新

概述

比較運算符用于比較兩個值的大小,然后返回一個布爾值,表示是否滿足指定的條件。

2 > 1 // true

上面代碼比較2是否大于1,返回true。

注意,比較運算符可以比較各種類型的值,不僅僅是數(shù)值。

JavaScript 一共提供了8個比較運算符。

  • > 大于運算符
  • < 小于運算符
  • <= 小于或等于運算符
  • >= 大于或等于運算符
  • == 相等運算符
  • === 嚴(yán)格相等運算符
  • != 不相等運算符
  • !== 嚴(yán)格不相等運算符

這八個比較運算符分成兩類:相等比較和非相等比較。兩者的規(guī)則是不一樣的,對于非相等的比較,算法是先看兩個運算子是否都是字符串,如果是的,就按照字典順序比較(實際上是比較 Unicode 碼點);否則,將兩個運算子都轉(zhuǎn)成數(shù)值,再比較數(shù)值的大小。

非相等運算符:字符串的比較

字符串按照字典順序進行比較。

'cat' > 'dog' // false
'cat' > 'catalog' // false

JavaScript 引擎內(nèi)部首先比較首字符的 Unicode 碼點。如果相等,再比較第二個字符的 Unicode 碼點,以此類推。

'cat' > 'Cat' // true'

上面代碼中,小寫的c的 Unicode 碼點(99)大于大寫的C的 Unicode 碼點(67),所以返回true

由于所有字符都有 Unicode 碼點,因此漢字也可以比較。

'大' > '小' // false

上面代碼中,“大”的 Unicode 碼點是22823,“小”是23567,因此返回false。

非相等運算符:非字符串的比較

如果兩個運算子之中,至少有一個不是字符串,需要分成以下兩種情況。

(1)原始類型值

如果兩個運算子都是原始類型的值,則是先轉(zhuǎn)成數(shù)值再比較。

5 > '4' // true
// 等同于 5 > Number('4')
// 即 5 > 4

true > false // true
// 等同于 Number(true) > Number(false)
// 即 1 > 0

2 > true // true
// 等同于 2 > Number(true)
// 即 2 > 1

上面代碼中,字符串和布爾值都會先轉(zhuǎn)成數(shù)值,再進行比較。

這里需要注意與NaN的比較。任何值(包括NaN本身)與NaN使用非相等運算符進行比較,返回的都是false

1 > NaN // false
1 <= NaN // false
'1' > NaN // false
'1' <= NaN // false
NaN > NaN // false
NaN <= NaN // false

(2)對象

如果運算子是對象,會轉(zhuǎn)為原始類型的值,再進行比較。

對象轉(zhuǎn)換成原始類型的值,算法是先調(diào)用valueOf方法;如果返回的還是對象,再接著調(diào)用toString方法,詳細解釋參見《數(shù)據(jù)類型的轉(zhuǎn)換》一章。

var x = [2];
x > '11' // true
// 等同于 [2].valueOf().toString() > '11'
// 即 '2' > '11'

x.valueOf = function () { return '1' };
x > '11' // false
// 等同于 (function () { return '1' })() > '11'
// 即 '1' > '11'

兩個對象之間的比較也是如此。

[2] > [1] // true
// 等同于 [2].valueOf().toString() > [1].valueOf().toString()
// 即 '2' > '1'

[2] > [11] // true
// 等同于 [2].valueOf().toString() > [11].valueOf().toString()
// 即 '2' > '11'

({ x: 2 }) >= ({ x: 1 }) // true
// 等同于 ({ x: 2 }).valueOf().toString() >= ({ x: 1 }).valueOf().toString()
// 即 '[object Object]' >= '[object Object]'

嚴(yán)格相等運算符

JavaScript 提供兩種相等運算符:=====。

簡單說,它們的區(qū)別是相等運算符(==)比較兩個值是否相等,嚴(yán)格相等運算符(===)比較它們是否為“同一個值”。如果兩個值不是同一類型,嚴(yán)格相等運算符(===)直接返回false,而相等運算符(==)會將它們轉(zhuǎn)換成同一個類型,再用嚴(yán)格相等運算符進行比較。

本節(jié)介紹嚴(yán)格相等運算符的算法。

(1)不同類型的值

如果兩個值的類型不同,直接返回false

1 === "1" // false
true === "true" // false

上面代碼比較數(shù)值的1與字符串的“1”、布爾值的true與字符串"true",因為類型不同,結(jié)果都是false。

(2)同一類的原始類型值

同一類型的原始類型的值(數(shù)值、字符串、布爾值)比較時,值相同就返回true,值不同就返回false

1 === 0x1 // true

上面代碼比較十進制的1與十六進制的1,因為類型和值都相同,返回true

需要注意的是,NaN與任何值都不相等(包括自身)。另外,正0等于負0。

NaN === NaN  // false
+0 === -0 // true

(3)復(fù)合類型值

兩個復(fù)合類型(對象、數(shù)組、函數(shù))的數(shù)據(jù)比較時,不是比較它們的值是否相等,而是比較它們是否指向同一個地址。

{} === {} // false
[] === [] // false
(function () {} === function () {}) // false

上面代碼分別比較兩個空對象、兩個空數(shù)組、兩個空函數(shù),結(jié)果都是不相等。原因是對于復(fù)合類型的值,嚴(yán)格相等運算比較的是,它們是否引用同一個內(nèi)存地址,而運算符兩邊的空對象、空數(shù)組、空函數(shù)的值,都存放在不同的內(nèi)存地址,結(jié)果當(dāng)然是false。

如果兩個變量引用同一個對象,則它們相等。

var v1 = {};
var v2 = v1;
v1 === v2 // true

注意,對于兩個對象的比較,嚴(yán)格相等運算符比較的是地址,而大于或小于運算符比較的是值。

var obj1 = {};
var obj2 = {};

obj1 > obj2 // false
obj1 < obj2 // false
obj1 === obj2 // false

上面的三個比較,前兩個比較的是值,最后一個比較的是地址,所以都返回false。

(4)undefined 和 null

undefinednull與自身嚴(yán)格相等。

undefined === undefined // true
null === null // true

由于變量聲明后默認(rèn)值是undefined,因此兩個只聲明未賦值的變量是相等的。

var v1;
var v2;
v1 === v2 // true

嚴(yán)格不相等運算符

嚴(yán)格相等運算符有一個對應(yīng)的“嚴(yán)格不相等運算符”(!==),它的算法就是先求嚴(yán)格相等運算符的結(jié)果,然后返回相反值。

1 !== '1' // true
// 等同于
!(1 === '1')

上面代碼中,感嘆號!是求出后面表達式的相反值。

相等運算符

相等運算符用來比較相同類型的數(shù)據(jù)時,與嚴(yán)格相等運算符完全一樣。

1 == 1.0
// 等同于
1 === 1.0

比較不同類型的數(shù)據(jù)時,相等運算符會先將數(shù)據(jù)進行類型轉(zhuǎn)換,然后再用嚴(yán)格相等運算符比較。下面分成幾種情況,討論不同類型的值互相比較的規(guī)則。

(1)原始類型值

原始類型的值會轉(zhuǎn)換成數(shù)值再進行比較。

1 == true // true
// 等同于 1 === Number(true)

0 == false // true
// 等同于 0 === Number(false)

2 == true // false
// 等同于 2 === Number(true)

2 == false // false
// 等同于 2 === Number(false)

'true' == true // false
// 等同于 Number('true') === Number(true)
// 等同于 NaN === 1

'' == 0 // true
// 等同于 Number('') === 0
// 等同于 0 === 0

'' == false  // true
// 等同于 Number('') === Number(false)
// 等同于 0 === 0

'1' == true  // true
// 等同于 Number('1') === Number(true)
// 等同于 1 === 1

'\n  123  \t' == 123 // true
// 因為字符串轉(zhuǎn)為數(shù)字時,省略前置和后置的空格

上面代碼將字符串和布爾值都轉(zhuǎn)為數(shù)值,然后再進行比較。具體的字符串與布爾值的類型轉(zhuǎn)換規(guī)則,參見《數(shù)據(jù)類型轉(zhuǎn)換》一章。

(2)對象與原始類型值比較

對象(這里指廣義的對象,包括數(shù)組和函數(shù))與原始類型的值比較時,對象轉(zhuǎn)換成原始類型的值,再進行比較。

具體來說,先調(diào)用對象的valueOf()方法,如果得到原始類型的值,就按照上一小節(jié)的規(guī)則,互相比較;如果得到的還是對象,則再調(diào)用toString()方法,得到字符串形式,再進行比較。

下面是數(shù)組與原始類型值比較的例子。

// 數(shù)組與數(shù)值的比較
[1] == 1 // true

// 數(shù)組與字符串的比較
[1] == '1' // true
[1, 2] == '1,2' // true

// 對象與布爾值的比較
[1] == true // true
[2] == true // false

上面例子中,JavaScript 引擎會先對數(shù)組[1]調(diào)用數(shù)組的valueOf()方法,由于返回的還是一個數(shù)組,所以會接著調(diào)用數(shù)組的toString()方法,得到字符串形式,再按照上一小節(jié)的規(guī)則進行比較。

下面是一個更直接的例子。

const obj = {
  valueOf: function () {
    console.log('執(zhí)行 valueOf()');
    return obj;
  },
  toString: function () {
    console.log('執(zhí)行 toString()');
    return 'foo';
  }
};

obj == 'foo'
// 執(zhí)行 valueOf()
// 執(zhí)行 toString()
// true

上面例子中,obj是一個自定義了valueOf()toString()方法的對象。這個對象與字符串'foo'進行比較時,會依次調(diào)用valueOf()toString()方法,最后返回'foo',所以比較結(jié)果是true。

(3)undefined 和 null

undefinednull只有與自身比較,或者互相比較時,才會返回true;與其他類型的值比較時,結(jié)果都為false。

undefined == undefined // true
null == null // true
undefined == null // true

false == null // false
false == undefined // false

0 == null // false
0 == undefined // false

(4)相等運算符的缺點

相等運算符隱藏的類型轉(zhuǎn)換,會帶來一些違反直覺的結(jié)果。

0 == ''             // true
0 == '0'            // true

2 == true           // false
2 == false          // false

false == 'false'    // false
false == '0'        // true

false == undefined  // false
false == null       // false
null == undefined   // true

' \t\r\n ' == 0     // true

上面這些表達式都不同于直覺,很容易出錯。因此建議不要使用相等運算符(==),最好只使用嚴(yán)格相等運算符(===)。

不相等運算符

相等運算符有一個對應(yīng)的“不相等運算符”(!=),它的算法就是先求相等運算符的結(jié)果,然后返回相反值。

1 != '1' // false

// 等同于
!(1 == '1')


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

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號