相等运算符==和===

169 阅读5分钟

==和===之间的区别 · ==在执行比较之前,会将变量转换为相同类型。这称为类型强制。 · ===并没有做任何类型转换(强制),返回true是只有在两个被比较的变量类型是相同的情况下。

ES6规格对每一种语法行为的描述都分成两部分:先是总体行为描述,然后是实现的算法细节。==和===运算符的总体描述都只有一句话: The comparison x == y, where x and y are values, produces true or false. 上面这句话的意思是,相等运算符用于比较两个值,返回true或false。 下面是算法细节:

1. ReturnIfAbrupt(x).
2. ReturnIfAbrupt(y).
3. If Type(x) is the same as Type(y), then 
4. Return the result of performing Strict Equality Comparison x === y.
5. If x is null and y is undefined, return true.
6. If x is undefined and y is null, return true.
7. If Type(x) is Number and Type(y) is String,
8. return the result of the comarison x == ToNumber(y).
9. If Type(x) is String and Type(y) is Number,
10. return the result of the comparison ToNumber(x) == (y).
11. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
12. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
13. If Type(x) is either String, Number, or Symbol and Type(y) is Object, then
14. return the result of the comparison x == ToPrimitive(y)
15. If Type(x) is Object and Type(y) is either String, Number, or Symbol, then
16. return the result of the comparison ToPrimitive(x) == y
17. Return false.

`
上面这段算法一共又12步,意思如下:
1、如果x不是正常值(比如抛出一个错误),中断执行。
2、如果y不是正常值,中断执行。
3、如果Type(x)与Type(y)相同,执行严格相等运算 x===y。
4、如果x是null,y是undefined,返回true。
5、如果x是undefined, y是null,返回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)的结果。
10Type(x)是字符串或数值或Symbol值,Type(y)是对象,返回x == ToPrimitive(y)的结果。
11、如果Type(x)是对象,Type(y)是字符串或数值Symbol值,返回ToPrimitive(x) == y的结果。
12、返回false.
由于0的类型是数值,null的类型是Null,这是ES6规格规定的,是内部类型运算的结果,跟typeof运算无关。因此,上面的前11步得不到结果,要到第12步才能得到false.
0 == null // false
`

===运算符的细节:

1. If Type(x) is different from Type(y), return false.
2. If Type(x) is Undefined, return True.
3. If Type(x) is Null, return True.
4. If Type(x) is Number, then
	a. If x is NaN, return false.
    b. If y is NaN, return false.
    c. If x is the same Number value as y, return true.
    d. If x is +0 and y is -0, return true.
    e. If x is -0 and y is +0, return true.
    f. Return false.
5. If Type(x) is String, then
	a. If x and y are exactily the same serquence of code units(same length and same code units at corresponding indices), return true.
    b. Else, return false.
6. If Type(x) is Boolean, then
	a. If x and y are both true or both false, return true.
    b. Else, return false.
7. If x and y are the same Symbol value, return true.
8. If x and y are the same Object value, return true.
9. Return false.

example:

let x = 1
let y = 1
let z = "1" // z 是一个字符串

console.log(x == y)
console.log(x === y)
console.log(x == z)
console.log(x === z)

// 输出结果:
true
true
true
false

== 和 === 的运行效率: 理论上,当比较具有相同类型的变量时,两个运算符使用的算法相同,所以两个运算符的性能应该相似。当比较的变量类型不同时,===运算符的性能应该优于==运算符,因为它不需要执行额外的强制转换类型操作。下面对此进行一些性能测试。

test1:

let x = 1
let y = 1
let z = "1"

console.log(x == y)
// console.log(x === y)
// console.log(x == z)
// console.log(x === z)

true

[Done] exited with code=0 in 0.823 seconds

test2: 

let x = 1
let y = 1
let z = "1"

// console.log(x == y)
console.log(x === y)
// console.log(x == z)
// console.log(x === z)

结果:
true

[Done] exited with code=0 in 0.803 seconds

test3:

let x = 1
let y = 1
let z = "1"

// console.log(x == y)
// console.log(x === y)
console.log(x == z)
// console.log(x === z)

结果:
true

[Done] exited with code=0 in 0.817 seconds

test4:

let x = 1
let y = 1
let z = "1"

// console.log(x == y)
// console.log(x === y)
// console.log(x == z)
console.log(x === z)

结果:
false

[Done] exited with code=0 in 0.827 seconds

可以看出,性能差距很小几乎可以忽略,但是如果考虑到一下这点,则性能完全无关紧要,如果不需要强制转换类型时,请不要使用==,因为可能会得到意外的结果。例如: "1" == true 或 "" == 0将返回true。 简而言之,在所有地方始终使用===,除非需要强制转换类型时使用==。

不等式运算符: !=和!== 与==和===在检查不平等方面类似。 · != 在检查不等式之前,如果变量是不同类型,则转化为相同类型进行值得比较。 · !== 检查要比较得两个变量得类型和值。

let x = 1
let y = 1
let z = "1"

console.log(x != y)
console.log(x !== y)
console.log(x != z)
console.log(x !== z)

结果:
false
false
false
true

以上是对原始数据类型得相等和不相等得探索。引用类型,如数组或对象呢? 如果有两个具有相同内容得数组,是否可以像对原始类型的变量伊信仰使用相等运算符来比较它们呢? 看个例子:

let a1 = [1, 2, 3, 4, 5]
let a2 = [1, 2, 3, 4, 5]

console.log(a1 == a2)
console.log(a1 === a2)
结果:
false
false

这里,==和===返回相同的结果:false. 因为在这里a1和a2都指向内存中的不同对象。既是数组内容一样,但它们本质上具有不同的值。这种情况同样适用与其他引用类型。 ES6:Object.is() 有时使用===运算符进行值比较,但是着并不完美,有几个行为令人困惑的示例:

console.log(+0 === -0)
console.log(NaN === NaN)
结果:
true
false

为了是比较不那么混乱,ES6引入了一种新方法:OBject.is()。它接受两个参数,如果值和类型都相等,则返回true。本质上,它与===运算符相同,但是没有怪癖。如下:

console.log(Object.is(2, 2))
console.log(Object.is(2, "2"))

console.log(Object.is(+0, -0))
console.log(Object.is(NaN, NaN))

结果:
true
false
false
true