Table of Contents

JavaScript Array includes() method checks whether an array contains a particular value and returns true or false. It is useful for clear membership checks, such as confirming that a selected option, permission, or label is present. Unlike indexOf(), it can find NaN. The sections below add practical examples for object arrays, conditional searches, value matching, and sparse arrays.

Syntax and Formal Specification

The method signature is includes(searchElement, fromIndex).

javascript
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3));         // true
console.log(numbers.includes(3, 3));      // false (search starts at index 3)
console.log(numbers.includes(3, -3));     // true (starts at index 2)

Parameters

  • searchElement — The value to search for. Compared via SameValueZero, which treats NaN as equal to itself and treats +0 and -0 as equal.
  • fromIndex (optional) — The index at which to start searching. Defaults to 0. Negative values are treated as offsets from the end (-1 is the last element). If fromIndex >= length, the search starts beyond the array and immediately returns false. If negative and beyond -length, the search starts from index 0.

Return Value

A boolean: true if a matching element is found within the search range, false otherwise.

javascript
console.log([].includes(1));         // false (empty array)
console.log([undefined].includes()); // true (undefined is present)
console.log([1, 2].includes());      // false (undefined not present)

Generic Usage on Array-Like Objects

Because the method is generic, it can be applied to arguments, DOM collections, and custom objects with length:

javascript
const arrayLike = { 0: "a", 1: "b", 2: "c", length: 3 };
const found = Array.prototype.includes.call(arrayLike, "b");
console.log(found);   // true

function findInArgs(value) {
  return Array.prototype.includes.call(arguments, value);
}
console.log(findInArgs("x"));   // false

Strings have their own includes() method (String.prototype.includes), which performs a substring search rather than an element comparison. Do not conflate the two.

Performance: Linear Search and Comparison with indexOf()

includes() runs in O(n) time for an array of n elements. It short-circuits at the first match, so its effective cost depends on how early the target appears. In the worst case (target at the end or absent), it visits every element.

javascript
const big = new Array(1_000_000).fill(0);
const start = performance.now();
big.includes(0);                    // Match at index 0, near-instant
console.log(performance.now() - start);

const start2 = performance.now();
big.includes(-1);                   // Full scan, ~O(n)
console.log(performance.now() - start2);

includes() vs indexOf() !== -1

For pure existence checks, includes() is the preferred idiom. Both return the same result for primitive values (except for NaN), and modern engines optimize includes() to be at least as fast as indexOf() !== -1, often marginally faster because it avoids producing a sentinel -1 that must be compared. The primary advantages of includes() are:

  1. Readability: arr.includes(x) is a direct expression of “does this array include x?”
  2. Correctness for NaN: arr.indexOf(NaN) !== -1 is always false even if NaN is present.
  3. Boolean return type: No need to add !== -1 at the call site.
javascript
const values = [1, 2, NaN, 3];
console.log(values.indexOf(NaN) !== -1);   // false (BUG!)
console.log(values.includes(NaN));         // true (correct)

Array includes() vs String includes()

Both methods share the name but differ in semantics. Array includes() compares elements by SameValueZero; String includes() searches for a substring.

javascript
console.log(["hello"].includes("hello"));         // true (whole string element)
console.log("hello world".includes("hello"));     // true (substring)
console.log(["hello world"].includes("hello"));   // false (not whole element)

The fromIndex Optimization

When the target is known to appear late, a positive fromIndex can skip a prefix and reduce scanning:

javascript
const arr = new Array(1_000_000).fill(0);
arr[999_999] = -1;

// Full scan: near-instant (match at index 0)
arr.includes(0);

// Skipped prefix: efficient
arr.includes(-1, 500_000);

A negative fromIndex is an offset from the end, then the search proceeds forward. For example, -1 starts at the last item and checks only that position; earlier items will not be searched.

javascript
const arr = [1, 2, 3, 4, 5];
console.log(arr.includes(5, -1));         // true (starts at index 4)
console.log(arr.includes(1, -1));         // false (starts at index 4)
console.log(arr.includes(1, -100));       // true (clamped to 0)

Check values with the expected type and spelling

includes() compares a complete array element with the value you pass; it does not convert one type into another or perform a partial text search. For strings, the comparison is case-sensitive. Use the same data type and spelling that the array stores.

const values = [1, "1", "JavaScript"];

console.log(values.includes(1));          // true
console.log(values.includes("1"));        // true
console.log(values.includes("01"));       // false
console.log(values.includes("javascript")); // false

In the first two checks, the values match different elements: the number 1 and the string “1” are not interchangeable. For a case-insensitive text check, normalize both the search value and array values, or use a callback method such as some().

Using includes() with objects

For objects, includes() checks whether the exact same object reference is in the array. It does not compare object properties. Two separate objects with identical fields are still different references.

const firstUser = { id: 7, name: "Asha" };
const users = [firstUser];

console.log(users.includes(firstUser)); // true
console.log(users.includes({ id: 7, name: "Asha" })); // false

const hasUserId = users.some(user => user.id === 7);
console.log(hasUserId); // true

If the goal is to match by an ID, name, or another property, some() is usually the right choice for a yes-or-no result. Use find() when you need the matching object, or findIndex() when you need its position.

Use some() for a condition instead of an exact value

includes() accepts a value to compare, not a predicate function. Passing a function does not make it test each item; it simply looks for that function object as an array element. For conditions such as “is any score over 90?” or “does any task remain incomplete?”, use some().

const scores = [72, 84, 93];

console.log(scores.includes(score => score > 90)); // false
console.log(scores.some(score => score > 90));     // true

The first call searches for the callback function itself, which is not stored in scores. The second call runs the condition for each score and stops when it finds a match. For a single known value, includes() stays simpler and more direct.

includes() and sparse array holes

includes() treats an empty slot, or hole, in a sparse array like undefined for its search. This is different from indexOf(), which skips empty slots. If your application distinguishes an unassigned position from a position that explicitly stores undefined, test whether the index is an own property as well.

const sparse = new Array(3);
const explicitUndefined = [undefined];

console.log(sparse.includes(undefined)); // true
console.log(sparse.indexOf(undefined));  // -1
console.log(explicitUndefined.includes(undefined)); // true

Most arrays used in everyday application code are dense, so every index has a value. The distinction matters when arrays are created with a length and populated only at selected positions, or when code deletes array elements with the delete operator.

Use the Boolean result in a condition

Because includes() already returns a Boolean, you can use it directly in an if statement. This reads naturally for lists of supported roles, selected filters, or required features.

const enabledFeatures = ["search", "export", "darkMode"];

if (enabledFeatures.includes("export")) {
  console.log("Export is available");
}

If you need to display every missing required value, combine membership checks with filter() rather than stopping at the first result:

const required = ["search", "export", "backup"];
const missing = required.filter(feature => !enabledFeatures.includes(feature));

console.log(missing); // ["backup"]

This pattern is clear for short lists. For very large lists with many repeated membership checks, convert the values to a Set once and use set.has(value) for each lookup.