I'm familiar with NaN
being "weird" in JavaScript, i.e., NaN === NaN
always returns false
, as described here. So one should not make ===
comparisons to check for NaN
, but use isNaN(..) instead.
So I was surprised to discover that
> [NaN].includes(NaN)
true
This seems inconsistent. Why have this behavior?
How does it even work? Does the includes
method specifically check isNaN
?
According to MDN's document say that
Note: Technically speaking,
includes()
uses thesameValueZero
algorithm to determine whether the given element is found.
const x = NaN, y = NaN;
console.log(x == y); // false -> using ‘loose’ equality
console.log(x === y); // false -> using ‘strict’ equality
console.log([x].indexOf(y)); // -1 (false) -> using ‘strict’ equality
console.log(Object.is(x, y)); // true -> using ‘Same-value’ equality
console.log([x].includes(y)); // true -> using ‘Same-value-zero’ equality
Object.is()
and ===
is in their treatment of signed zeroes and NaNs.The .includes()
method uses SameValueZero
algorithm for checking the equality of two values and it considers the NaN
value to be equal to itself.
The SameValueZero
algorithm is similar to SameValue
, but the only difference is that the SameValueZero
algorithm considers +0
and -0
to be equal.
The Object.is()
method uses SameValue
and it returns true for NaN
.
console.log(Object.is(NaN, NaN));
The behavior of .includes()
method is slightly different from the .indexOf()
method; the .indexOf()
method uses strict equality comparison to compare values and strict equality comparison doesn't consider NaN
to be equal to itself.
console.log([NaN].indexOf(NaN));
Information about different equality checking algorithms can be found at MDN: