JavaScript 中存在各种比较,例如常见的 ==
(loosely equal) ===
(strictly equal) Object.is
isNaN
Number.isNaN
等等,
这些操作符或者函数都可以用来比较/判断。本文继续根据 ECMA规范 来学习和比较他们之间的差异。
SameType 和 SameValue
在了解 JavaScript 提供的这些比较/判断方法前,我们需要了解其内部提供的 SameType(x, y)
和 SameValue(x, y)
两个抽象方法。

不难看出 SameType
是完全的对类型进行对比,如果类型一致则返回 true
,否则返回 false
。
对于 SameValue
则是在 SameType
的前提上对具体的值进行判断,其中对 Number
类型和 非Number
类型做了区分。其中:
Number
中是对NaN
+0
-0
一类的特殊值做了处理- 非
Number
类型中其实就是对他们的比较做出了规范的定义


Strictly Equal

我们首先看严格相等,规范中首先判断的是类型,如果类型不一致,则直接不想等,后续则使用 Numer.equal
对数字类型进行判断。
值得注意的是,
Number::equal
和Number::sameValue
对于NaN
+0
-0
的判断:
Number::equal
中,一侧为NaN
则直接为false
,一侧为+0
一侧为-0
认为是 trueNumber::sameValue
中,两侧同时为NaN
返回true
,一侧为+0
一侧为-0
返回false
即:sameValue
相对equal
比较严格。

Loosely Equal

宽松相等的话,当类型一致的话判断方式就直接沿用了 Strictly Equal
,后续都是对类型不一致时情况的处理。
可以看到大致逻辑是:
undefined
和null
- 当一侧为
Number
/BigInt
时,另一侧则会转换成Number
/BigInt
类型 - 当一侧为
Boolean
类型的时候,就会将Boolean
转换成Number
在重新使用loosely equal
判断 - 如果有一侧为对象的话,则将其会转换成原始值后调用
loosely equal
比较 - 对于一侧为
Number
一侧为BigInt
时,如果一侧不是有限值,则直接返回false
Object.is

这里直使用了上面的 SameValue
进行判断,而且也没有其他特殊情况的处理。
isNaN

首先将传入的参数做了转换处理,然后判断转换后的值是不是 NaN
,是则返回 true
。
提示这里说,判断
X
是否为NaN
的可靠方法是使用形式为X !== X
的表达式。当且仅当X
为NaN
时,结果才为真。 但是需要先排除X
是对象的前提(即X
需要是原始值)。
Number.isNaN

还是比较简洁的,需要注意的就是 Notes 提到的,与 isNaN
的区别在于: isNaN
会把参数做一次转换.
至此,总结了这几种比较方式,本质上还是通过 SameType
SameValue
及其他底层的抽象方法和一些具体情况
进行处理。需要注意的可能就是一些特殊情况以及特殊情况对于的转换逻辑。