Table of Contents

The JavaScript Array indexOf() method searches an array for a specified value and returns the index of its first match. If the value is not found, it returns -1. Because array indexes start at 0, the returned number can be used to locate an element or check whether an item exists. In this guide, you’ll learn its syntax, how to search from a chosen position, and how it compares with includes() and findIndex().

Syntax and Formal Specification

The method signature is indexOf(searchElement, fromIndex).

javascript
const fruits = ["apple", "banana", "cherry", "banana"];
console.log(fruits.indexOf("banana"));       // 1
console.log(fruits.indexOf("banana", 2));    // 3
console.log(fruits.indexOf("grape"));        // -1

Parameters

  • searchElement — The value to locate in the array. Compared via strict equality, the comparison used by ===. Therefore, NaN does not match itself; use includes() when a membership check must detect NaN.

  • fromIndex (optional) — The index at which to start searching. Defaults to 0. Negative values are treated as offsets from the end: -1 means start from the last element, -2 from the second-to-last, and so on. If fromIndex >= length, the search starts beyond the array and immediately returns -1. If negative and beyond -length, the search starts from index 0.

Return Value

An integer: the index of the first match, or -1 if no match is found. Never returns undefined or throws on absence.

javascript
const arr = [10, 20, 30];
console.log(arr.indexOf(20));        // 1
console.log(arr.indexOf(40));        // -1
console.log(arr.indexOf());          // -1 (undefined not present)
console.log([undefined].indexOf());  // 0  (undefined is present)

Generic Usage on Array-Like Objects

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

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

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

Strings also support indexOf() natively, but that method has different semantics (substring search rather than element equality), so calling Array.prototype.indexOf on a string is unusual. Rely on String.prototype.indexOf instead.

Performance: Linear Search and Complexity

indexOf() runs in O(n) time for an array of n elements. It stops at the first match, so the average 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.indexOf(0);                       // Match at index 0, near-instant
console.log(performance.now() - start);

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

fromIndex as an Optimization Lever

A positive fromIndex restricts the scan to [fromIndex, length), reducing work. A negative fromIndex shifts the starting point but still scans to the end—do not assume a negative index reduces the work when the target is near the array’s end.

javascript
const arr = [1, 2, 3, 4, 5, 6, 7, 8];
arr.indexOf(8, 3);         // Starts at index 3, finds at 7
arr.indexOf(1, -1);        // Starts at last index (7), returns -1
arr.indexOf(8, -2);        // Starts at index 6, finds at 7
arr.indexOf(2, -100);      // Clamped to index 0, returns 1

Search for duplicates and continue from an index

indexOf() returns only the first match it encounters at or after the starting position. If a value appears more than once, pass a fromIndex to continue looking after an earlier result.

const fruits = ["apple", "banana", "cherry", "banana", "date"];

const firstBanana = fruits.indexOf("banana");
const nextBanana = fruits.indexOf("banana", firstBanana + 1);

console.log(firstBanana); // 1
console.log(nextBanana); // 3

To collect every matching position, repeat the search and advance the starting index after each match. Adding 1 is important: searching again from the same index would return the same result forever.

const values = ["x", "y", "x", "z", "x"];
const positions = [];
let position = values.indexOf("x");

while (position !== -1) {
  positions.push(position);
  position = values.indexOf("x", position + 1);
}

console.log(positions); // [0, 2, 4]

This approach works well for occasional searches. If a program repeatedly needs to check membership in a large collection, a Set may be a better data structure.

Check whether a value exists

A common use is testing whether an array contains a value. Since the first valid array index is 0, compare the result with -1 explicitly. Do not use the result directly as a Boolean: index 0 is falsy, while -1 is truthy.

const permissions = ["read", "write"];

if (permissions.indexOf("read") !== -1) {
  console.log("Reading is allowed");
}

const first = permissions.indexOf("read");
console.log(Boolean(first)); // false, even though "read" was found

For a direct true-or-false answer, includes() is often clearer:

console.log(permissions.includes("write")); // true
console.log(permissions.includes("admin")); // false

Choose indexOf() when you need the position for another operation, such as reading or removing that entry. Choose includes() when you only need to know whether the value is present.

indexOf(), includes(), findIndex(), and lastIndexOf()

These methods all help search arrays, but their results and matching rules differ.

  • indexOf(value) returns the first matching index or -1. It compares values using strict equality.
  • includes(value) returns a Boolean and can detect NaN.
  • findIndex(callback) returns the first index whose element passes a test function. Use it when matching an object by one of its properties or when the condition is more complex than equality.
  • lastIndexOf(value) searches from the end and returns the last matching index, or -1.
const scores = [4, 8, 8, 10];

console.log(scores.indexOf(8));      // 1
console.log(scores.lastIndexOf(8));  // 2
console.log(scores.findIndex(n => n > 8)); // 3

The fromIndex argument for lastIndexOf() also counts from the end when negative, but its direction is reversed: it sets the last index to inspect rather than where a forward search begins.

How values are compared

indexOf() uses strict equality for array elements. That means the number 2 does not match the string "2", and NaN does not match itself with this method. Use includes() if you need a simple membership check that can find NaN.

const mixed = [2, "2", NaN];

console.log(mixed.indexOf(2));       // 0
console.log(mixed.indexOf("2"));     // 1
console.log(mixed.indexOf(NaN));     // -1
console.log(mixed.includes(NaN));    // true

For objects, strict equality checks whether the exact same object reference is present. It does not compare object properties automatically.

const user = { id: 7 };
const users = [{ id: 7 }, user];

console.log(users.indexOf({ id: 7 })); // -1
console.log(users.indexOf(user));      // 1

const userIndex = users.findIndex(item => item.id === 7);
console.log(userIndex); // 0

The two objects with an id of 7 look alike, but they are different objects. Use findIndex() with a callback when the matching rule should be based on a property.

Removing an item after finding it

You can combine indexOf() with splice() when you want to remove the first matching value. Always check for -1 first. Passing -1 directly as a splice start would target the last element, which is often not what you intend.

const tasks = ["plan", "review", "publish"];
const index = tasks.indexOf("review");

if (index !== -1) {
  tasks.splice(index, 1);
}

console.log(tasks); // ["plan", "publish"]

If the same value appears several times, this removes only the first occurrence. To remove every matching value while keeping the original array, use filter():

const tags = ["news", "tips", "news"];
const withoutNews = tags.filter(tag => tag !== "news");

console.log(withoutNews); // ["tips"]
console.log(tags);        // ["news", "tips", "news"]

These examples show why getting the index and checking the not-found case are separate steps. The method only reports a position; the code that uses that position decides what change to make.