前言

当我们想在JavaScript中比较两个值时, 第一时间想到的就是相等运算符(==)或全等运算符(===),由于相等运算符在比较时可能会触发存在强制类型转换,我们更喜欢后者。但是全等运算符也不完全准确,比如,+0和-0在JavaScript引擎中被表示为两个完全不同的实体,但是如果用全等运算符(===)来比较,得到的结果是两者相等了,又如,NaN===NaN的返回结果是false。

为此,ES6引入了Object.is()方法来弥补全等运算符的不准确运算,下面我们来介绍一下这个API的用法和功能

语法

Object.is(value1, value2);

参数说明

value1:第一个需要比较的值。

value2:第二个需要比较的值。

返回值:表示两个参数是否相同的布尔值

执行机制 

Object.is() 判断两个值是否相同。如果下列任何一项成立,则两个值相同:

  1. 两个值都是 undefined
  2. 两个值都是 null
  3. 两个值都是 true 或者都是 false
  4. 两个值是由相同个数的字符按照相同的顺序组成的字符串
  5. 两个值指向同一个对象
  6. 两个值都是数字并且
  • 都是正零 +0
  • 都是负零 -0
  • 都是 NaN
  • 都是除零和 NaN 外的其它同一个数字

这种相等性判断逻辑和传统的相等运算符 (==) 运算不同,==  运算符会对它两边的操作数做隐式类型转换(如果它们类型不同),然后才进行相等性比较,(所以才会有类似 "" == false 等于 true 的现象),但 Object.is 不会做这种类型转换。

但是需要注意的是,== 运算符对操作数进行隐式类型转换也是有“规律”的,比如,null转换为Number类型是0,但是0==null 的返回值是false。这种“规律”与JavaScript的内部有关,想要彻底理解就要去读JavaScript的规格了,而对于相等运算符(==)的运算,它的规格翻译如下:

假定判断 x==y ,

  1. 如果x不是正常值(比如抛出一个错误),中断执行。
  2. 如果y不是正常值,中断执行。
  3. 如果Type(x)Type(y)相同,执行严格相等运算x === y
  4. 如果xnullyundefined,返回true
  5. 如果xundefinedynull,返回true
  6. 如果Type(x)是数值,Type(y)是字符串,返回x == ToNumber(y)的结果。
  7. 如果Type(x)是字符串,Type(y)是数值,返回ToNumber(x) == y的结果。
  8. 如果Type(x)是布尔值,返回ToNumber(x) == y的结果。
  9. 如果Type(y)是布尔值,返回x == ToNumber(y)的结果。
  10. 如果Type(x)是字符串或数值或Symbol值,Type(y)是对象,返回x == ToPrimitive(y)的结果。
  11. 如果Type(x)是对象,Type(y)是字符串或数值或Symbol值,返回ToPrimitive(x) == y的结果。
  12. 返回false

知道了这些再看 0 == null 返回 false 就很明白了:

由于0的类型是数值,null的类型是 Null(注意:这是规格4.3.13 小节的规定,是内部 Type 运算的结果,跟typeof运算符无关)。因此上面的前 11 步都得不到结果,要到第 12 步才能得到结果,结果为false。 

当然这是补充的知识,现在我们再回过头来看Object.is()

Object.is()这种相等性判断逻辑与 ===运算符的判定方式也不一样。===运算符(和 == 运算符)将数字值 -0 和 +0 视为相等,并认为Number.NaN不等于  NaN。

实例演示

Object.is('foo', 'foo');     // true 两个相同字符串
Object.is('1',1)   // false 不会自动转换
Object.is('foo', 'bar');     // false
Object.is([], []);           // false
Object.is(null, null);       // true 
Object.is(window, window);   // true 相同对象

var foo = { a: 1 };
var bar = { a: 1 };
Object.is(foo, foo);         // true
Object.is(foo, bar);         // false  不同对
 
// 特例
Object.is(0, -0);            // false
Object.is(0, +0);            // true
Object.is(-0, -0);           // true
Object.is(NaN, 0/0);         // true