本文首发于公众号:攻城狮追风
前言
在Js中,大家比较熟悉的是==和===相等比较运算符,对应在ECMA标准中定义了这两种运算符的算法,即Abstract Equality Comparison和Strict Equality Comparison。除了这两种,ECMA标准中还定义了几种相等比较,如SameValue和SameValueZero算法。本篇将从标准的角度介绍这几种相等算法的异同。
SameValue
先看一下ECMA对SameValue的定义,摘自ECMA标准。
SameValue(x, y)
- ReturnIfAbrupt(x).
- ReturnIfAbrupt(y).
- If Type(x) is different from Type(y), return false.
- If Type(x) is Undefined, return true.
- If Type(x) is Null, return true.
- If Type(x) is Number, then
- a. If x is NaN and y is NaN, return true.
- b. If x is +0 and y is -0, return false.
- c. If x is -0 and y is +0, return false.
- d. If x is the same Number value as y, return true.
- e. Return false.
- If Type(x) is String, then
- a. If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices) return true; otherwise, return false.
- If Type(x) is Boolean, then
- a. If x and y are both true or both false, return true; otherwise, return false.
- If Type(x) is Symbol, then
- a. If x and y are both the same Symbol value, return true; otherwise, return false.
- Return true if x and y are the same Object value. Otherwise, return false.
简单总结一下SameValue(x, y)的比较方式:
- 类型不同,返回false
- 如果x类型为Undefined或Null,返回true
- 如果类型为Number,比较略复杂:NaN和NaN比较返回true,+0和-0、-0和+0比较返回false
- String, Boolean, Symbol以及Object比较与===相同。
ECMAScript 6规范中定义了
Object.is()方法,即实现了SameValue算法。 案例:
SameValue(true, 1) => false
SameValue({}, {}) => false
SameValueZero
ECMA标准中,对SameValueZero的定义说明,它与SameValue仅在对+0、-0的处理上略有不同,具体如下:
- +0和-0比较返回true, -0和+0比较返回true
ES7规范中引入的
Array.prototype.includes方法即按照SameValueZero算法来判断是否相等。
Abstract Equality Comparison
相等算法明确了JS中等于运算符==的比较规则,操作数相等会返回true。如下介绍等于算法x==y的内容:
- 1.如果x和y的类型相同,返回
x===y的结果 - 2.null==undefined返回true,undefined==null返回true
- 3.如果一个操作数是字符串,另一个是数值,则尝试将字符串转换为数值,再比较是否相等
- 4.如果任一操作数是布尔值,则将其转换为数值再比较是否相等。false转换成0,true转换成1
- 5.如果一个操作数是对象,另一个不是,则调用对象的valueOf()方法获取原始值,在进行相等比较
- 6.返回false 我们根据该算法看几个案例
案例1:true == 1 // 返回true
根据相等算法第4条,将true转换成1,变成1===1,返回true
案例2:"5" == 5 // 返回true
根据相等算法第3条,将"5"转换成5,返回true
Strict Equality Comparison
全等算法明确了JS中全等运算符===的比较规则,操作数全等会返回true。如下介绍全等算法x===y的细则:
- 1.如果两个操作数类型不同,返回false
- 2.undefined===undefined返回true,null===null返回true
- 3.如果类型是数值,a:如果任一操作数是NaN,返回false b:如果x和y是同一数值,返回true c:+0===-0返回true,-0===+0返回true;d:返回false
- 4.如果类型是字符串,x与y有相同的码元序列则返回true,否则返回false
- 5.如果操作数为布尔值,x和y同为false或者同为true时,返回true。否则返回false
- 6.如果x与y为相同的Symbol值,返回true
- 7.如果x与y为相同的Object对象,返回true
- 8.返回false 我们根据该算法看几个案例
"5" === 5 // 由于类型不同,返回false
null === undefined // 类型不同,返回false
四种算法对比案例
| x | y | Abstract Equality Comparison(==) | Strict Equality Comparison(===) | SameValue(Object.is) | SameValueZero |
|---|---|---|---|---|---|
| undefined | undefined | true | true | true | true |
| null | null | true | true | true | true |
| true | true | true | true | true | true |
| false | false | true | true | true | true |
| +0 | -0 | true | true | false | true |
| 0 | false | true | false | false | false |
| "" | 0 | true | false | false | false |
| [1,2] | "1,2" | true | false | false | false |
| null | undefined | true | false | false | false |
| {a: 1} | {a:1} | false | false | false | false |
| NaN | NaN | false | false | true | true |
小结
本篇根据ECMAScript 6的规范,详解了四种相等算法,其中有三种方法在JS语言中已经实现。ES6规范引入的Object.is()实现了SameValue算法;相等操作符==实现了Abstract Equality Comparison算法;全等操作符===实现了Strict Equality Comparison算法。
各种相等算法略有不同,区别主要在于类型转换、对NaN、null、undefined、+0、-0等特殊值的处理,至于为什么要定义这么多不同的算法,我的理解是ES规范中为了应对不同的场景定义各种算法来满足相等的比较,大家也可以说说自己的理解。