How Array.prototype.includes Works in JavaScript
Array.prototype.includes() is a built-in JavaScript
method that checks if an array contains a specified value, returning a
boolean result (true or false). This article
explains the underlying mechanism of
Array.prototype.includes(), focusing on its use of the
SameValueZero comparison algorithm, its handling of search
offsets with fromIndex, and how it evaluates different data
types such as primitives, NaN, and object references.
The SameValueZero Algorithm
Under the hood, JavaScript’s Array.prototype.includes()
determines element existence using the SameValueZero
equality algorithm defined in the ECMAScript specification. This
differentiates it from both strict equality (===) and the
indexOf() method, which uses the
IsStrictlyEqual algorithm.
The primary differences in SameValueZero are:
NaNHandling: In standard JavaScript equality (===),NaN === NaNevaluates tofalse. Consequently,indexOf(NaN)returns-1. However,SameValueZerotreatsNaNas equal toNaN. Therefore,[NaN].includes(NaN)returnstrue.- Zero Handling: Both
+0and-0are considered equal, meaning[-0].includes(+0)evaluates totrue.
const numbers = [1, 2, NaN, -0];
// NaN evaluation
console.log(numbers.includes(NaN)); // true
console.log(numbers.indexOf(NaN)); // -1
// Signed zero evaluation
console.log(numbers.includes(+0)); // trueSearch Parameters and Iteration
The includes() method accepts two arguments:
array.includes(searchElement, fromIndex)searchElement: The value to locate within the array.fromIndex(optional): The zero-based position at which to begin searching. It defaults to0.
Offset Behavior
(fromIndex)
The search iteration processes elements sequentially based on
fromIndex:
- Positive Index: If
fromIndex >= 0, the search begins at that index and proceeds to the end of the array. IffromIndex >= array.length, the method returnsfalseimmediately without searching. - Negative Index: If a negative integer is provided,
the starting index is calculated as
array.length + fromIndex. For example, in an array of length 5, afromIndexof-2starts the search at index3. - Clamped Negative Index: If
array.length + fromIndex < 0, the entire array is searched starting from index0.
const items = ['a', 'b', 'c', 'd'];
console.log(items.includes('b', 1)); // true (starts at index 1)
console.log(items.includes('b', 2)); // false (starts at index 2)
console.log(items.includes('c', -2)); // true (starts at index 2)
console.log(items.includes('a', -10)); // true (clamped to index 0)Primitive Types vs. Reference Types
Array.prototype.includes() compares elements by value
for primitives and by reference for objects.
- Primitives (strings, numbers, booleans, symbols, null,
undefined): Evaluated by their actual value according to
SameValueZero. - Reference Types (objects, arrays, functions):
Evaluated by memory reference, not structural equality. Two distinct
objects with identical properties will evaluate to
false.
const obj = { id: 1 };
const list = [obj, { id: 2 }];
// Found because the reference matches
console.log(list.includes(obj)); // true
// Not found because the object reference is distinct
console.log(list.includes({ id: 1 })); // falseSparse Arrays and Undefined Elements
When searching sparse arrays (arrays with empty slots),
Array.prototype.includes() treats empty slots as having the
value undefined. This allows includes() to
find undefined in array holes, unlike older array iteration
methods like forEach() or indexOf(), which
skip empty slots entirely.
const sparseArray = [1, , 3]; // Contains an empty slot at index 1
console.log(sparseArray.includes(undefined)); // true
console.log(sparseArray.indexOf(undefined)); // -1