理清JS中等於(==)和全等(===)那些糾纏不清的關係

ThinkMore發表於2017-10-23

文章主要梳理了一下,不同型別的值在判斷是否相等時,存在的各種特殊關係,並給出判斷是否相等的可靠方法。

首先說明兩個關係:等於不一定全等,全等則一定等於;不等於則一定不全等,不全等不一定不等於。在文章中,能用全等的地方,等於也是一定成立的;等於不成立的地方,全等也一定不成立,相信大家都能理解,不再作特殊說明。

判斷0的符號

0 === -0,但是它們不完全相同,如何判斷?

先看幾個關係:

Infinity === Infinity // true
Infinity === -Infinity // false
1/-0 === -Infinity // true
1/0 === Infinity // true複製程式碼

所以有:

1/-0 === 1/-0 // true
1/0 === 1/0 // true
1/-0 === 1/0 //false複製程式碼

所以,0其實是有符號的,可以使用以上辦法判斷。

判斷undefinednull

還是先看幾組關係:

undefined === undefined // true
null === null // true
null == undefined // true
null === undefined // false複製程式碼

所以,如果只判斷一個變數值是否為null或者變數未定義,只需使用“==”即可,但是如果要清楚地區分nullundefined,那就要進一步比較了。下面是兩個判斷nullundefined的方法:

Object.prototype.toString.call(null) === "[object, Null]"
Object.prototype.toString.call(undefined) === "[object, Undefined]"

// 還有一個關係注意一下,我看有些面試題會問到:
typeof null === "object"
typeof undefined === "undefined"複製程式碼

判斷正規表示式

兩個完全一樣的正規表示式其實是不相等的:

var a = /[1-9]/;
var b = /[1-9]/;
a == b // false複製程式碼

因為a,b其實是兩個正規表示式物件,同樣是引用型別的:

typeof a === "object" // true
typeof b === "object" // true複製程式碼

如果我們希望能夠比較兩個正規表示式內容是否一樣,而不關心記憶體地址,那麼只需要比較兩個表示式字串是否相等即可:

var a = /[1-9]/;
var b = /[1-9]/;
'' + a === '' + b // true
注:'' + /[1-9]/ === '/[1-9]/'複製程式碼

字串的比較

這裡需要區分字串和字串物件
如果是字串,則直接使用“===”符號判斷即可:

var a = 'a string';
var b = 'a string';
a === b //true複製程式碼

但是,對於字串物件(引用型別),直接對比時,對比的仍然是記憶體地址:

var a = new String('a string');
var b = new String('a string');
a == b // false複製程式碼

如果關注字串內容是否相同,則可以將字串物件轉化為字串,再進行比較:

var a = new String('a string');
var b = new String('a string');
'' + a == '' + b // true

// 也可以使用toString方法比較:
a.toString() === b.toString() // true複製程式碼

所以,判斷兩個字串內容是否相同,最可靠的辦法是:

function isStringEqual(a, b) {
    return '' + a === '' + b;
}複製程式碼

數字的比較

同樣需要區分數值和數值物件:

var a = new Number(5);
var b = new Number(5);

// 直接對比時不相等
a == b //false

// 使用+符號,轉化成數值的對比
+a === +b //true複製程式碼

但是,有一個特殊的值必須特殊對待,即NaN,它也是Number型別的

Object.prototype.toString.call(NaN) // "[object Number]"
typeof NaN // "number"複製程式碼

同時,它的如下關係導致了以上判斷數值是否相等的方法出現了例外:

NaN == NaN //false
+NaN == +NaN // false
注:+NaN還是NaN複製程式碼

如何在兩個數值都是NaN的情況下判斷兩者是相等的呢?看一個命題:對於任意非NaN的數值物件或數值(a),+a === +a始終成立,假如該等式不成立,則a即為NaN。所以,如果已知a為NaN,如何在b也是NaN時,希望判斷兩者是相等的呢?

if(+a !== +a) return +b !== +b;複製程式碼

解釋如下:

假設a為NaN,判斷條件成立,如果b也是NaN,返回語句的表示式成立,返回true,表示兩者相等(都是NaN);如果b不是NaN,返回語句的表示式不成立,返回false,表示兩者不相等。

將以上判斷的邏輯整合為一個判斷函式,即:

function isNumberEqual(a, b) {
    if (+a !== +a) return +b !== +b; // 處理特殊情況
    return +a === +b;
}複製程式碼

Date物件對比

物件的對比也不能直接使用等號判斷,我們還是隻關心日期值是否相同,所以,將日期轉化為毫秒數值,然後對比數值是否相同

var a = new Date('2017-9-7');
var b = new Date('2017-9-7');
a == b //false
+a === +b //true
注:+a的值為1504713600000,即,對應2017.9.7 00:00:00的毫秒數

效果和使用getTime()方法對比一樣
a.getTime() === b.getTime() // true複製程式碼

布林值物件的對比

物件不能直接對比,故,將布林值轉化為數值,然後對比

var a = new Boolean('123');
var b = new Boolean('123');
a == b //false
+a === +b //true
// 注: 布林值為真,前面加“+”,轉化為數值1,為假則轉為0複製程式碼

文中很多對比的方法,其實都可以找到對應的物件方法實現值的對比,本文最主要的還是提醒各位,在對比時,注意區分對比的是值還是物件,如果目的是對比值是否相等,則要進一步轉化。另外,特別注意各型別的值在對比時存在的特殊情況,以及特殊值之間的關係。

以上,希望對你有用。歡迎留言糾錯或補充。

相關文章