比較運(yùn)算符用于比較兩個(gè)值的大小,然后返回一個(gè)布爾值,表示是否滿足指定的條件。
2 > 1 // true
上面代碼比較2
是否大于1
,返回true
。
注意,比較運(yùn)算符可以比較各種類(lèi)型的值,不僅僅是數(shù)值。
JavaScript 一共提供了8個(gè)比較運(yùn)算符。
>
大于運(yùn)算符<
小于運(yùn)算符<=
小于或等于運(yùn)算符>=
大于或等于運(yùn)算符==
相等運(yùn)算符===
嚴(yán)格相等運(yùn)算符!=
不相等運(yùn)算符!==
嚴(yán)格不相等運(yùn)算符這八個(gè)比較運(yùn)算符分成兩類(lèi):相等比較和非相等比較。兩者的規(guī)則是不一樣的,對(duì)于非相等的比較,算法是先看兩個(gè)運(yùn)算子是否都是字符串,如果是的,就按照字典順序比較(實(shí)際上是比較 Unicode 碼點(diǎn));否則,將兩個(gè)運(yùn)算子都轉(zhuǎn)成數(shù)值,再比較數(shù)值的大小。
字符串按照字典順序進(jìn)行比較。
'cat' > 'dog' // false
'cat' > 'catalog' // false
JavaScript 引擎內(nèi)部首先比較首字符的 Unicode 碼點(diǎn)。如果相等,再比較第二個(gè)字符的 Unicode 碼點(diǎn),以此類(lèi)推。
'cat' > 'Cat' // true'
上面代碼中,小寫(xiě)的c
的 Unicode 碼點(diǎn)(99
)大于大寫(xiě)的C
的 Unicode 碼點(diǎn)(67
),所以返回true
。
由于所有字符都有 Unicode 碼點(diǎn),因此漢字也可以比較。
'大' > '小' // false
上面代碼中,“大”的 Unicode 碼點(diǎn)是22823,“小”是23567,因此返回false
。
如果兩個(gè)運(yùn)算子之中,至少有一個(gè)不是字符串,需要分成以下兩種情況。
(1)原始類(lèi)型值
如果兩個(gè)運(yùn)算子都是原始類(lèi)型的值,則是先轉(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
上面代碼中,字符串和布爾值都會(huì)先轉(zhuǎn)成數(shù)值,再進(jìn)行比較。
這里需要注意與NaN
的比較。任何值(包括NaN
本身)與NaN
使用非相等運(yùn)算符進(jìn)行比較,返回的都是false
。
1 > NaN // false
1 <= NaN // false
'1' > NaN // false
'1' <= NaN // false
NaN > NaN // false
NaN <= NaN // false
(2)對(duì)象
如果運(yùn)算子是對(duì)象,會(huì)轉(zhuǎn)為原始類(lèi)型的值,再進(jìn)行比較。
對(duì)象轉(zhuǎn)換成原始類(lèi)型的值,算法是先調(diào)用valueOf
方法;如果返回的還是對(duì)象,再接著調(diào)用toString
方法,詳細(xì)解釋參見(jiàn)《數(shù)據(jù)類(lèi)型的轉(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'
兩個(gè)對(duì)象之間的比較也是如此。
[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]'
JavaScript 提供兩種相等運(yùn)算符:==
和===
。
簡(jiǎn)單說(shuō),它們的區(qū)別是相等運(yùn)算符(==
)比較兩個(gè)值是否相等,嚴(yán)格相等運(yùn)算符(===
)比較它們是否為“同一個(gè)值”。如果兩個(gè)值不是同一類(lèi)型,嚴(yán)格相等運(yùn)算符(===
)直接返回false
,而相等運(yùn)算符(==
)會(huì)將它們轉(zhuǎn)換成同一個(gè)類(lèi)型,再用嚴(yán)格相等運(yùn)算符進(jìn)行比較。
本節(jié)介紹嚴(yán)格相等運(yùn)算符的算法。
(1)不同類(lèi)型的值
如果兩個(gè)值的類(lèi)型不同,直接返回false
。
1 === "1" // false
true === "true" // false
上面代碼比較數(shù)值的1
與字符串的“1”、布爾值的true
與字符串"true"
,因?yàn)轭?lèi)型不同,結(jié)果都是false
。
(2)同一類(lèi)的原始類(lèi)型值
同一類(lèi)型的原始類(lèi)型的值(數(shù)值、字符串、布爾值)比較時(shí),值相同就返回true
,值不同就返回false
。
1 === 0x1 // true
上面代碼比較十進(jìn)制的1
與十六進(jìn)制的1
,因?yàn)轭?lèi)型和值都相同,返回true
。
需要注意的是,NaN
與任何值都不相等(包括自身)。另外,正0
等于負(fù)0
。
NaN === NaN // false
+0 === -0 // true
(3)復(fù)合類(lèi)型值
兩個(gè)復(fù)合類(lèi)型(對(duì)象、數(shù)組、函數(shù))的數(shù)據(jù)比較時(shí),不是比較它們的值是否相等,而是比較它們是否指向同一個(gè)地址。
{} === {} // false
[] === [] // false
(function () {} === function () {}) // false
上面代碼分別比較兩個(gè)空對(duì)象、兩個(gè)空數(shù)組、兩個(gè)空函數(shù),結(jié)果都是不相等。原因是對(duì)于復(fù)合類(lèi)型的值,嚴(yán)格相等運(yùn)算比較的是,它們是否引用同一個(gè)內(nèi)存地址,而運(yùn)算符兩邊的空對(duì)象、空數(shù)組、空函數(shù)的值,都存放在不同的內(nèi)存地址,結(jié)果當(dāng)然是false
。
如果兩個(gè)變量引用同一個(gè)對(duì)象,則它們相等。
var v1 = {};
var v2 = v1;
v1 === v2 // true
注意,對(duì)于兩個(gè)對(duì)象的比較,嚴(yán)格相等運(yùn)算符比較的是地址,而大于或小于運(yùn)算符比較的是值。
var obj1 = {};
var obj2 = {};
obj1 > obj2 // false
obj1 < obj2 // false
obj1 === obj2 // false
上面的三個(gè)比較,前兩個(gè)比較的是值,最后一個(gè)比較的是地址,所以都返回false
。
(4)undefined 和 null
undefined
和null
與自身嚴(yán)格相等。
undefined === undefined // true
null === null // true
由于變量聲明后默認(rèn)值是undefined
,因此兩個(gè)只聲明未賦值的變量是相等的。
var v1;
var v2;
v1 === v2 // true
嚴(yán)格相等運(yùn)算符有一個(gè)對(duì)應(yīng)的“嚴(yán)格不相等運(yùn)算符”(!==
),它的算法就是先求嚴(yán)格相等運(yùn)算符的結(jié)果,然后返回相反值。
1 !== '1' // true
// 等同于
!(1 === '1')
上面代碼中,感嘆號(hào)!
是求出后面表達(dá)式的相反值。
相等運(yùn)算符用來(lái)比較相同類(lèi)型的數(shù)據(jù)時(shí),與嚴(yán)格相等運(yùn)算符完全一樣。
1 == 1.0
// 等同于
1 === 1.0
比較不同類(lèi)型的數(shù)據(jù)時(shí),相等運(yùn)算符會(huì)先將數(shù)據(jù)進(jìn)行類(lèi)型轉(zhuǎn)換,然后再用嚴(yán)格相等運(yùn)算符比較。下面分成幾種情況,討論不同類(lèi)型的值互相比較的規(guī)則。
(1)原始類(lèi)型值
原始類(lèi)型的值會(huì)轉(zhuǎn)換成數(shù)值再進(jìn)行比較。
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
// 因?yàn)樽址D(zhuǎn)為數(shù)字時(shí),省略前置和后置的空格
上面代碼將字符串和布爾值都轉(zhuǎn)為數(shù)值,然后再進(jìn)行比較。具體的字符串與布爾值的類(lèi)型轉(zhuǎn)換規(guī)則,參見(jiàn)《數(shù)據(jù)類(lèi)型轉(zhuǎn)換》一章。
(2)對(duì)象與原始類(lèi)型值比較
對(duì)象(這里指廣義的對(duì)象,包括數(shù)組和函數(shù))與原始類(lèi)型的值比較時(shí),對(duì)象轉(zhuǎn)換成原始類(lèi)型的值,再進(jìn)行比較。
具體來(lái)說(shuō),先調(diào)用對(duì)象的valueOf()
方法,如果得到原始類(lèi)型的值,就按照上一小節(jié)的規(guī)則,互相比較;如果得到的還是對(duì)象,則再調(diào)用toString()
方法,得到字符串形式,再進(jìn)行比較。
下面是數(shù)組與原始類(lèi)型值比較的例子。
// 數(shù)組與數(shù)值的比較
[1] == 1 // true
// 數(shù)組與字符串的比較
[1] == '1' // true
[1, 2] == '1,2' // true
// 對(duì)象與布爾值的比較
[1] == true // true
[2] == true // false
上面例子中,JavaScript 引擎會(huì)先對(duì)數(shù)組[1]
調(diào)用數(shù)組的valueOf()
方法,由于返回的還是一個(gè)數(shù)組,所以會(huì)接著調(diào)用數(shù)組的toString()
方法,得到字符串形式,再按照上一小節(jié)的規(guī)則進(jìn)行比較。
下面是一個(gè)更直接的例子。
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
是一個(gè)自定義了valueOf()
和toString()
方法的對(duì)象。這個(gè)對(duì)象與字符串'foo'
進(jìn)行比較時(shí),會(huì)依次調(diào)用valueOf()
和toString()
方法,最后返回'foo'
,所以比較結(jié)果是true
。
(3)undefined 和 null
undefined
和null
只有與自身比較,或者互相比較時(shí),才會(huì)返回true
;與其他類(lèi)型的值比較時(shí),結(jié)果都為false
。
undefined == undefined // true
null == null // true
undefined == null // true
false == null // false
false == undefined // false
0 == null // false
0 == undefined // false
(4)相等運(yùn)算符的缺點(diǎn)
相等運(yùn)算符隱藏的類(lèi)型轉(zhuǎn)換,會(huì)帶來(lái)一些違反直覺(jué)的結(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
上面這些表達(dá)式都不同于直覺(jué),很容易出錯(cuò)。因此建議不要使用相等運(yùn)算符(==
),最好只使用嚴(yán)格相等運(yùn)算符(===
)。
相等運(yùn)算符有一個(gè)對(duì)應(yīng)的“不相等運(yùn)算符”(!=
),它的算法就是先求相等運(yùn)算符的結(jié)果,然后返回相反值。
1 != '1' // false
// 等同于
!(1 == '1')
更多建議: