Equality in JavaScript
JavaScript defines 4 different algorithms for determining whether two values are equal:
- Abstract equality:
==
- Strict equality:
===
- SameValue:
Object.is()
- SameValueZero: Same as
Object.is
, except-0
is considered equal to+0
.
Strict Equality, SameValueZero, SameValue
Strict equality, SameValueZero, and SameValue are almost equivalent. They only differ in their handling of NaN
,
+0
, and -0
. For all other values, the last 3 algorithms are identical.
Strict Equality: NaN
is not strictly equal to any value, not even itself. In other words, NaN !== NaN
. Also, (+0) === (-0)
.
SameValue: The Object.is()
function implements the SameValue algorithm. With the SameValue algorithm, NaN
is equal to itself: Object.is(NaN, NaN) === true
. But, on the other hand, +0
is not equal to -0
: Object.is(+0, -0) === false
.
SameValueZero: There's no way to use SameValueZero directly, but the Array#includes()
method uses SameValueZero internally. So, to try out SameValueZero, you can use includes()
. The only difference between SameValue and SameValueZero is that SameValueZero treats +0
as equal to -0
: [+0].includes(-0) === true
.
As a developer, you should typically use ===
, with the understanding that you may need to add a special case if
you care about NaN
. The distinction between +0
and -0
is not important for most use cases.
Abstract Equality
Abstract equality has numerous differences. The abstract equality algorithm supports several implicit type conversions. Here's a brief overview:
- If
x
andy
are the same type, check ifx === y
. - If
x
andy
are both eithernull
orundefined
, returntrue
. - If
x
is a number andy
is a string, converty
to a number and then compare using===
. Similarly, ifx
is a boolean or string, andy
is a number, convertx
to a number. - If
x
ory
is a boolean, convert the other value of a number and compare them. - If
x
is an object andy
is a symbol, string, or number, try to convertx
to a primitive using valueOf() and then compare using===
.
In general, you should not use abstract equality. The one potential exception is checking for nullish values:
// Only true if `v === null` or `v === undefined`
v == null;
// Equivalent:
v === null || v === undefined;
ESLint has a rule to disallow == unless the right hand side is null.
Where These Equality Comparisons Are Used
The tricky part of these different equality comparisons is that different JavaScript methods use different
equality algorithms internally. For example, the Array#indexOf()
function uses strict equality, but Array#includes()
uses SameValueZero, which leads to different behavior when searching for NaN
in arrays:
[NaN].indexOf(NaN); // -1, not found!
[NaN].includes(NaN); // true, found!
Here's where these different equality comparisons are used:
- Strict Equality:
indexOf()
,lastIndexOf
,case
statements. - SameValueZero:
Set
values,Map
keys,includes()
. - SameValue: Used internally by
Object.defineProperty()
.