Array.prototype.findIndex()

find, but it hands back the position instead of the element. That makes it the reliable way to distinguish "matched a falsy value" from "matched nothing".

Array methodES2015Live demo
Common call
items.findIndex(x => x.id === id)
Returns
number — the index, or -1
Replaces
indexOf when you need a predicate rather than a value
Watch out
-1 is truthy, so compare it explicitly
array.findIndex(callback[, thisArg])
→ number

Demo

Live evaluation
Try:
Inputs
itemsnumber[]numbers, comma separated
thresholdnumberfirst index above this
Output
[1, 2, 3, 4].findIndex(x => x > 2)
2

The index of the first passing element comes back, and iteration stops there. A missing match gives -1, and an empty array gives -1 too. The advantage over find is precision: a result of 0 means "matched at the start" and -1 means "no match", whereas find returns the element itself and cannot distinguish a matched 0 from a failed search.

Parameters

NameTypeRequiredDescription
callbackFunctionyesCalled as callback(element, index, array). Iteration stops at the first truthy result.
thisArganyno (undefined)Value of `this` inside the callback. Ignored for arrow functions.

Return value

number — Index of the first element for which the callback returned truthy, or -1 when none did.

Common patterns

Find then replace
The index is what you need to write back.
const i = items.findIndex(x => x.id === id);
if (i !== -1) items[i] = updated;
Find then remove
Pairs with splice.
const i = items.findIndex(pred);
if (i !== -1) items.splice(i, 1);
Distinguish falsy match from no match
What find cannot do on its own.
const i = values.findIndex(v => v === 0);
const found = i !== -1;

Examples

1. Match in the middle
[1, 2, 3, 4].findIndex(x => x > 2)
Returns
2
2. No match
[1, 2, 3].findIndex(x => x > 99)
Returns
-1
3. Match at index 0
[0, 1].findIndex(x => x === 0)
Returns
0
4. find is ambiguous
[0, 1].find(x => x === 0)
Returns
0 // same as "not found"?
5. Empty array
[].findIndex(x => true)
Returns
-1
6. Predicate, not value
[{id: 1}].findIndex(o => o.id === 1)
Returns
0

Pitfalls

1. -1 is truthy
Same trap as indexOf. Testing the result directly is backwards: no match gives -1 which passes an if, and a match at index 0 gives 0 which fails one.
Backwards
if (items.findIndex(pred)) { /* "found" */ }
true when ABSENT, false at index 0
Compare explicitly
if (items.findIndex(pred) !== -1) { ... }
correct
2. It returns an index, not the element
Coming from find, it is easy to use the result as the value. You get a number, so property access silently yields undefined rather than throwing.
Index used as element
items.findIndex(pred).name
undefined
Index into the array
items[items.findIndex(pred)].name
the value
3. A braced callback with no return always gives -1
Without an explicit return the callback yields undefined, which is falsy, so nothing ever matches and the answer is always -1.
No return
[1, 2, 3].findIndex(x => { x > 1 })
-1
Return it
[1, 2, 3].findIndex(x => x > 1)
1

When to use

Use it
  • You need the position in order to replace or remove
  • Distinguishing a falsy match from no match at all
  • Matching by a predicate rather than by value
Reach for something else
  • You want the element → find
  • You are matching a plain value → indexOf
  • You only need a yes/no answer → some

Notes

Complexity
O(n) worst case; stops at the first match
Return
A number; -1 means absent, and -1 is truthy
CPython impl
V8: Builtins-array-findindex.tq
Memory
No allocation
Thread-safe
Single-threaded; mutating the source inside the callback is undefined behaviour for unvisited indices

FAQ

findIndex when you need the position — to replace, remove, or to tell a falsy match apart from no match. find when you just want the element and none of its possible values are falsy.

History

ES2015
find and findIndex added together.
ES2023
findLast and findLastIndex added for searching from the end.