理清JS中等于(==)和全等(===)那些纠缠不清的关系

文章主要梳理了一下,不一样类型的值在判断是否相等时,存在的各类特殊关系,并给出判断是否相等的可靠方法。面试

首先说明两个关系:等于不必定全等,全等则必定等于;不等于则必定不全等,不全等不必定不等于。在文章中,能用全等的地方,等于也是必定成立的;等于不成立的地方,全等也必定不成立,相信你们都能理解,再也不做特殊说明。正则表达式

判断0的符号

0 === -0,可是它们不彻底相同,如何判断?markdown

先看几个关系:函数

Infinity === Infinity // true
Infinity === -Infinity // false
1/-0 === -Infinity // true
1/0 === Infinity // true复制代码

因此有:spa

1/-0 === 1/-0 // true
1/0 === 1/0 // true
1/-0 === 1/0 //false复制代码

因此,0实际上是有符号的,可使用以上办法判断。prototype

判断undefinednull

仍是先看几组关系:code

undefined === undefined // true
null === null // true
null == undefined // true
null === undefined // false复制代码

因此,若是只判断一个变量值是否为null或者变量未定义,只需使用“==”便可,可是若是要清楚地区分nullundefined,那就要进一步比较了。下面是两个判断nullundefined的方法:orm

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复制代码

文中不少对比的方法,其实均可以找到对应的对象方法实现值的对比,本文最主要的仍是提醒各位,在对比时,注意区分对比的是值仍是对象,若是目的是对比值是否相等,则要进一步转化。另外,特别注意各种型的值在对比时存在的特殊状况,以及特殊值之间的关系。

以上,但愿对你有用。欢迎留言纠错或补充。

相关文章
相关标签/搜索