Two questions decide the method: do I match by value or by a predicate, and do I want a boolean, the item, or the index.
| Method | Matches by | Returns | No match |
|---|---|---|---|
includes(x, from?) |
SameValueZero | boolean |
false |
indexOf(x, from?) / lastIndexOf |
strict equality (===) |
index | -1 |
find(fn) / findLast(fn) |
predicate | element | undefined |
findIndex(fn) / findLastIndex(fn) |
predicate | index | -1 |
at(i) |
position | element | undefined |
includes vs indexOf. SameValueZero treats NaN as equal to itself (and 0 as equal to -0), so [NaN].includes(NaN) is true while [NaN].indexOf(NaN) is -1. indexOf also skips holes (it checks HasProperty), while includes reads them as undefined. Neither does deep comparison: objects match by reference, so use find/some with a predicate.
find family. The predicate receives (element, index, array), and iteration stops at the first truthy result. findLast and findLastIndex (ES2023) scan from the end, which avoids arr.slice().reverse().find(...). find returns undefined for no match, which is ambiguous if the array can hold undefined, so use findIndex there. All of them visit holes as undefined.
at. at(i) accepts negative integers, counting from the end: arr.at(-1) is the last item, where arr[-1] is just a property lookup of "-1" and gives undefined. The index is truncated to an integer (NaN becomes 0), and out-of-range returns undefined. It's generic, so it works on strings too.
includes and indexOf take a fromIndex; a negative one counts from the end.
For "is there any/all": some and every return booleans and stop early.