相等性判断

By yesmore on 2021-12-31
阅读时间 4 分钟
文章共 956
阅读量

同系列文章请查看:Github:pre-interview

相等性判断

概览

四种判断相等的方法

  • 全等:===
  • 等于:==
  • 零值相等:+0 === -0
  • 同值相等:-0 !== +0、NaN === NaN

JavaScript中提供有关相等判断的操作方法

  • 严格相等: === Strict Equality
  • 非严格(抽象相等/非约束) 相等:== Loose Equality
  • Object.is(v1, v2) ES6:判断两个参数是否是同一个值

Loose(自由的,不受限制的)

严格相等

严格相等特性

1 === ‘1’ false

1 === 2 false

  • 3)引用值必须是同一地址
1
2
3
4
5
6
var obj = {}
console.log(obj === obj) // true

console.log({} === {}) // false

// {} 等价于 new Object(),相当于new一个新对象
  • 4)NaN === NaN false

NaN 跟任何值都不相等

面试题:什么情况下 a !== a 成立?

答:a = NaN

  • 5)+0 === -0 // true
  • 6)+Infinity 与 -Infinity不相等(无穷)

Infinity === Infinity // true

面试题:什么情况下 a === a - 1 成立?

答:a = Infinity

- 7)全等对结果的预测更加清晰明确(不进行隐式转换) - 8)全等在不隐式类型转换的前提下,更快

非严格相等

Abstract equality

非严格相等特性

  • 1)隐式类型转换 - 等式两边都有可能被转换
  • 2)转换以后还是用严格相等来进行比较

关于隐式类型转换在非严格相等中的比较规律详见 MDN:非严格相等 ==

  • 3)任何对象都与 undefined null 不相等
1
2
3
// 测试
{} === undefined // Uncaught SyntaxError: Unexpected token '==='
// 报错是因为 {} 表示一个代码块,与 undefined 做相等判断是语法错误,没有意义。
1
2
({}) === undefined // false
({}) === null // false

补充:窄对象 Narrow Object -> document.all

1
document.all == undefined // true

但是 ,typeof document.all 打印出来为 "undefined";

document.all 在IE中是Object对象,其他浏览器为 "undefined",已废除。

  • 4)非严格相等不一定比严格相等差

零值相等(same-value-zero)

+0 === -0

同值相等(same-value)

1)-0 !== +0

证明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var obj = {}

Object.defineProperty(obj, 'myZero', {
value: -0,
writable: false,
configurable: false,
enumerable: false,
})

// +0/0 抛出异常,不能重新定义myZero属性,证明 +0与-0是不相等的值
Object.defineProperty(obj, 'myZero', {
value: +0,
})

// 报错:
Uncaught TypeError: Cannot redefine property: myZero
at Function.defineProperty (<anonymous>)
at 相等性判断.js:10

2)NaN === NaN

用相同方法证明:

1
2
3
4
5
6
7
8
9
10
11
Object.defineProperty(obj, 'myNaN', {
value: NaN,
writable: false,
configurable: false,
enumerable: false,
})

Object.defineProperty(obj, 'myNaN', {
value: NaN,
})
// 不报错

注意:同值相等的底层实现是基于 Object.is()(ES6) 实现,ES5并没有暴露JS引擎的同值相等方法

3)Object.is()

实现了同值相等

1
2
3
4
5
var a = 1
var b = '1'

var cpis = Object.is(a, b)
console.log(cpis) // false
1
2
3
4
5
var a = +0
var b = -0

var cpis = Object.is(a, b)
console.log(cpis) // false
1
2
3
4
5
var a = NaN
var b = NaN

var cpis = Object.is(a, b)
console.log(cpis); // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const res = Object.is(undefined, undefined)
console.log(res) // true

const res = Object.is(null, null)
console.log(res) // true

const res = Object.is('1', '1')
console.log(res) // true

const res = Object.is(1, 1)
console.log(res) // true

var obj = {}
const res = Object.is(obj, obj) // 同一个引用
console.log(res) // true

const res = Object.is({}, {}) // 不同引用
console.log(res) // false

const res = Object.is(+0, +0)
console.log(res) // true

总结:Object.is() 参数为两个值,返回值为同值相等判断的bool结果,判断标准就是同值相等(-0 !== +0、NaN === NaN)。

与严格相等的区别

  • -0 !== +0
  • NaN === NaN

与非严格相等的区别

  • 不进行隐式转换

手写 Object.is 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Object.myIs = function (a, b) {
if (a === b) {
// 两者都为0,返回 true
// 若分别为-0、+0,则Infinity !== -Infinity,返回 false
// 1 / +0 = Infinity
// 1 / -0 = -Infinity
return (a !== 0) || (1 / a === 1 / b)
}

// 排除 NaN 情况
return a !== a && b !== b
}

// test
console.log(Object.myIs(1, 1)); // true
console.log(Object.myIs({}, {})) // false
var obj = {}
console.log(Object.myIs(obj, obj)) // true
console.log(Object.myIs(+0, -0)) // false
console.log(Object.myIs(NaN, NaN)) // true

Tips: Please indicate the source and original author when reprinting or quoting this article.