在说明Object.is()与===、==的区别之前,我们先分别介绍Object.is()与比较操作符。
一、严格相等===
全等操作符比较两个值是否相等,两个被比较的值在比较前都不进行隐式转换。如果两个被比较的值具有不同的类型,这两个值是不全等的,否则,如果两个被比较的值类型相同,值也相同,并且都不是number类型时,两个值全等。最后两个值都是number类型,当两个都不是NaN,并且数值相同,或是两个值分别是+0和-0时,两个值被认为是全等的。
恒等规则:
- 如果类型不同,就不相等
- 如果两个都是数值,并且是同一个值,那么相等;有一个NaN就不相等
- 如果两个都是字符串,每个位置的字符都一样,那么相等;否则不相等
- 如果两个值都是同样的Boolean值,那么相等。
- 如果两个值都引用同一个对象或函数,那么相等,即两个对象的物理地址也必须保持一致;否则不相等。
- 如果两个值都是null,或者都是undefined,那么相等。
var num = 0;
var obj = new String('0');//object
var str = '0';//string
var b = false;
console.log(num === num);//true
console.log(obj === obj);//true
console.log(str === str);//true
console.log(num === obj);//false
console.log(num === str);//false
console.log(obj === str);//false
console.log(null === undefined);//false
console.log(obj === null);//false
console.log(obj === undefined);//false
二、非严格模式==
相等操作符比较两个值是否相等,在比较前将两个比较的值转换为相同类型。在转换后(等式的一边/两边都可能被转换),最终的比较方式等同于全等操作符===的比较方式。相等操作符满足交换规律。
恒等规则:
- 如果一个是null、一个是undefined,那么相等。
- 如果一个是字符串,一个是数值,把字符串转换成数值再进行比较。
- 如果任一值是true,把它转换成 1 再比较;如果任一值是false,把它转换成 0 再比较。
- 如果一个是对象,另一个是数值或字符串,把对象转换成基础类型的值再比较。对象转换成基础类型,利用它的toString或者valueOf方法。
- JS的核心内置类,会尝试valueOf先于toString;但有一个是例外——Date,Date利用的是toString转换。
- 非JS核心的对象,令说(比较麻烦,我也不大懂)。
- 任何其他组合,都不相等。
"1" == true:类型不等,true 会先转换成数值 1 ,
现在变成 “1” == 1 ,再把 “1” 转换成 1 ,比较 1 == 1 , 相等。
var num = 0;
var obj = new String('0');//object
var str = '0';//string
var b = false;
console.log(num == num);//true
console.log(obj == obj);//true
console.log(str == str);//true
console.log(num == obj);//true
console.log(num == str);//true
console.log(obj == str);//true
console.log(null == undefined);//true
console.log(obj == null);//false
console.log(obj == undefined);//false
有些开发者认为,最好永远都不要使用相等操作符。全等操作符的结果更容易预测,并且因为没有隐式转换,全等比较的操作会更快。
三、Object.is()
Object.is(),其行为与===基本一致,不过有两处不同:
- +0不等于-0。
- NaN等于自身。
Object.is()判断两个值是否相同。如果下列任何一项成立,则两个值相同:
- 两个值都是undefined
- 两个值都是null
- 两个值都是true/false
- 两个值是由相同个数的字符按照相同的顺序组成的字符串
- 两个值指向同一个对象
- 两个值都是数字并且都是正零+0/都是负零-0
- 都是NaN
- 都是除零和NaN外的其它同一个数字
这种相等性判断逻辑和传统的==运算不同,==运算符会对它两边的操作数做隐式类型转换(如果他们类型不同),然后才进行相等性比较,(所以才会有类似" " == false 等于true的现象),但Object.is()不会做这种类型转换。
这与===运算符的判定方式也不一样。===运算符(和==运算符)将数字值-0和+0视为相等,并认为Number.NaN不等于NaN。
Object.is('muzidigbig','muzidigbig');//true
Object.is(window,window);//true
Object.is([], []) //false
Object.is('foo','bar');//false
Object.is(NaN,NaN);//Object.is(NaN,NaN);
var foo = {a:1};
var bar = {a:1};
Object.is(foo,foo);//true
Object.is(foo,bar);//false
Object.is(null,null);//true
//特例
Object.is(0,-0);//false
Object.is(0,+0);//true
Object.is(-0,-0);//true
Object.is(NaN,0/0);//true
四、详解Object.is()与比较操作符===、==
==(或者!=)操作在需要的情况下自动进行了类型转换。
===(或者!==)操作不会执行任何转换。
===在比较值和类型时,可以说比==更快。
[10] == 10 //true
[10] === 10 //false
'10' == 10 //true
'10' === 10 //false
NaN == 0 //false
NaN === 0 //false
'' == false //true;但true == '0' false
'' === false //false
而在ES6中,Object.is()类似于===,但在三等号判断的基础上特别处理了NaN、-0和+0,保证-0和+0不再相同,但Object.is(NaN,NaN)会返回true。
Object.is()和传统的==运算符不同,==运算符会对它两边的操作数做隐式的类型转换(如果它们是不同的值的话),然后才进行相等性比较,(所以才会有类似" " ==false为true的现象),但Object.is()不会做这种类型转换。
而且,即便严格相等运算符===不会对操作数进行类型转换,但它不能区分两个不同的数字+0和-0,还会把两个NaN看成不相等的。