How Lodash _.includes Checks for NaN
In JavaScript, standard strict equality checks fail when identifying
NaN because NaN === NaN evaluates to
false. This article explores how Lodash’s
_.includes method overcomes this native limitation by
utilizing the SameValueZero equality algorithm alongside an
internal self-inequality check, ensuring that NaN values
within arrays and collections are reliably and securely detected.
The NaN Comparison Problem in JavaScript
Under the ECMAScript specification, NaN (Not-a-Number)
is unique because it is the only value in JavaScript that is not equal
to itself:
console.log(NaN === NaN); // false
console.log([NaN].indexOf(NaN)); // -1Because native methods historically relied on the Strict Equality
Comparison algorithm (===), methods like
Array.prototype.indexOf could not locate
NaN.
The SameValueZero Algorithm
Lodash avoids this failure by standardizing its collection and comparison utilities around the SameValueZero comparison algorithm.
SameValueZero behaves almost identically to strict equality
(===), with two major exceptions:
+0and-0are considered equal.NaNandNaNare considered equal.
By following this specification, _.includes ensures
mathematical consistency across search operations.
How Lodash Implements NaN Detection
To execute SameValueZero efficiently without performance
overhead, Lodash employs a conditional branch inside its internal
indexing pipeline (primarily within baseIndexOf and
associated helper utilities).
1. The Self-Inequality Test
Lodash first determines whether the target value is NaN
by exploiting JavaScript's self-inequality property:
function isNaNValue(value) {
return value !== value;
}If target !== target evaluates to true, the
search value is guaranteed to be NaN.
2. Branching to
nanIndexOf
Once the target value is identified as NaN, Lodash
bypasses standard strict-equality loops and directs the search to a
specialized scanning routine, historically implemented as
nanIndexOf or an equivalent custom loop using
baseFindIndex:
function nanIndexOf(array, fromIndex) {
let index = fromIndex - 1;
const { length } = array;
while (++index < length) {
const value = array[index];
if (value !== value) {
return index;
}
}
return -1;
}This loop inspects each element in the collection and checks if the
element is not equal to itself (value !== value). When an
element satisfies this condition, it confirms the presence of
NaN at that index.
3. Returning the Result
If nanIndexOf finds a valid match (returning an index of
0 or greater), _.includes evaluates the result
to true. If the loop terminates without finding an element
that satisfies value !== value, it returns -1,
resolving _.includes to false.
Through this mechanism, Lodash securely verifies the presence of
NaN while avoiding false negatives and preserving
high-performance execution for all standard data types.