JS相等判定全解析:==、===、Object.is()、同值相等、零值相等

459 阅读3分钟

JS相等判别全解析:==、===、Object.is()、同值相等、零值相等

希望这篇文章能成为您日后查询相等判别知识的字典

==(相等)

相等操作符会先进行强制类型转换,再确定操作数是否相等。

类型转换规则

  • 任一操作符是布尔值,将其转换为数值。
  • 一个操作符是字符串,一个操作符是数值,先将字符串转换为数值。
  • 一个操作数是对象,另一个不是,将对象转换为原始值。

比较规则

  • null和undefined相等。
  • null和undefined不能转换为其他类型的值进行比较。(只要和null和undefined比较的不是null或undefined,就返回false)。
  • 如果有任一操作数是NaN,相等操作符返回false。

输出示例

console.log(null == undefined);// true
console.log(NaN == NaN);// false

经典面试题 - [] == ![]

面试官经常会问,为什么[] == ![],实际上就是按照上述规则进行类型转换与比较的过程

console.log([] == ![]);// true
  1. ![]会被转换为false
  2. 对于任一操作符是布尔值,将其转换为数值。false => 0
  3. 一个操作符是对象,另一个不是,取得对象原始值。[] => ''
  4. 一个操作符是字符串,一个操作符是数值,将字符串转为数值。'' => 0
  5. 0 == 0

===(全等)

全等操作符不会进行强制类型转换,只要操作数的类型不同或者引用数据类型的引用地址不同,都会返回false。

特殊情况

// 浮点数特殊情况
console.log(-0 === +0);//true
console.log(NaN === NaN);//false

// 类型不同的值始终不相等
console.log(1 === '1'); // false
console.log(true === 1); // false
console.log(null === undefined); // false

// 两个对象引用同一个内存地址才被认为是相等的
let obj1 = { a: 1 };
let obj2 = { a: 1 };
console.log(obj1 === obj2); // false (不同的引用)
console.log(obj1 === obj1); // true (相同的引用)
console.log([] === []);// false

除了 === 之外,数组索引查找方法也使用严格相等,包括 Array.prototype.indexOf()、Array.prototype.lastIndexOf()、TypedArray.prototype.index()、TypedArray.prototype.lastIndexOf() 和 case 匹配。这意味着你不能使用 indexOf(NaN) 查找数组中 NaN 值的索引,也不能将 NaN 用作 case 值在 switch 语句中匹配任何内容。

Object.is() | 同值相等(SameValue)

为什么将Object.is()同值相等(SameValue)放在一起呢?相同的判别规则。

同值相等由Object.is()方法提供。

Object.is()提供了一种更严格的相等比较方法,解决了===无法正确处理NaN和-0/+0的问题

特殊情况判定规则

// 正确的0、-0、+0相等/不等判定
console.log(Object.is(+0, -0));//false
console.log(Object.is(+0, 0));//true
console.log(Object.is(-0, 0));//false

// 正确的NaN相等判定
console.log(Object.is(NaN, NaN));//true

对比===

console.log(Object.is(-0, +0));//false
console.log(-0 === +0);//true

console.log(Object.is(NaN, NaN));//true
console.log(NaN === NaN);//false

Object.is()判定多个值相等

//工具函数:要检查超过两个值,递归地利用相等性传递即可
function recursivelyCheckEqual(x, ...rest) {
  return Object.is(x, rest[0]) &&
    (rest.length < 2 || recursivelyCheckEqual(...rest));
}

零值相等(SameValueZero)

将NaN视作相等,将+0和-0视作相等。

Map数据结构基于零值相等算法,我们可以借助Map数据结构验证:

const m = new Map();

//Map内部使用SameValueZero比较操作,基本上相当于使用严格对象相等的标准来检查键的匹配性
const a = 0/"",//NaN
      b = 0/"";//NaN
const pz = +0;
const nz = -0;

console.log(a === b);//false
console.log(pz === nz);//true

m.set(a, "foo");
m.set(pz, "bar");

console.log(m.get(b));// foo
console.log(m.get(nz));// bar

自定义代码实现

零值相等不作为 JavaScript API 公开,但可以通过自定义代码实现:

function SameValueZero(x, y) {
  if (typeof x === 'number' && typeof y === 'number') {
    return x === y || (x !== x && y !== y)
  }
  return x === y
}

console.log(SameValueZero(NaN, NaN));// true
console.log(SameValueZero(-0, +0));// true