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-0is 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
xandyare the same type, check ifx === y. - If
xandyare both eithernullorundefined, returntrue. - If
xis a number andyis a string, convertyto a number and then compare using===. Similarly, ifxis a boolean or string, andyis a number, convertxto a number. - If
xoryis a boolean, convert the other value of a number and compare them. - If
xis an object andyis a symbol, string, or number, try to convertxto 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,casestatements. - SameValueZero:
Setvalues,Mapkeys,includes(). - SameValue: Used internally by
Object.defineProperty().