What you'll be able to do
By the end of this page you should be able to keep every matching item with filter, get the first matching item with find, get its position with findIndex, and choose the right tool instead of forcing map or a full loop for every search.
Previous post: forEach and map.
Who this is for
- People who write nested
ifs insideforjust to keep some rows - Beginners who use
filterwhen they only needed one item - Anyone who checks
findresults without handlingundefined
You can skip this if you already pick filter for many matches and find / findIndex for the first. Come back when you treat a one-item filter array like a single value.
filter: keep every match (new array)
filter returns a new array with only the items where your callback returns a truthy value. The original list is unchanged.
const scores = [4, 9, 2, 10, 7];
const passing = scores.filter(function (score) {
return score >= 7;
});
console.log(passing); // [9, 10, 7]
Scenario A — show only published posts. posts.filter((p) => p.status === "published").
Scenario B — remove empty strings from a tag list. tags.filter((t) => t.trim().length > 0).
If nothing matches, you get [] — an empty array, not null.
find: first match or undefined
find stops at the first item that passes the test and returns that item (not an array). If nothing matches, you get undefined.
const users = [
{ id: 1, name: "Asha" },
{ id: 2, name: "Ben" },
];
const ben = users.find(function (user) {
return user.id === 2;
});
console.log(ben); // { id: 2, name: "Ben" }
Scenario A — open one user by id. find is the right shape: one object or nothing.
Scenario B — “first tag that starts with j”. Same idea on strings.
Always guard: if (!ben) { ... } before reading ben.name.
findIndex: position of the first match
findIndex is like find, but returns the index (a number). No match → -1 (not undefined).
const tags = ["css", "javascript", "html"];
const i = tags.findIndex(function (tag) {
return tag === "javascript";
});
console.log(i); // 1
Scenario A — replace one item in place. Find the index, then tags[i] = "js" if i !== -1.
Scenario B — remove one item later with splice. You need the index; find alone is not enough.
Check for -1 before using the index as if it were valid.
Picking the right “one item” method
| Need | Use |
|---|---|
| Many matches as a list | filter |
| First matching value | find |
| First matching index | findIndex |
| Only “does any match?” | some (next post) |
Scenario A — wrong: filter then [0]. Works, but allocates a whole array when find was enough.
Scenario B — wrong: find then treat it like an array. find is one item; calling .map on it will throw if you get undefined or a non-array value.
Callbacks return a yes/no test
For these three methods the callback should answer “does this item count?” — usually a boolean expression.
nums.filter((n) => n > 0);
nums.find((n) => n > 0);
nums.findIndex((n) => n > 0);
Scenario A — readable named function. function isActive(user) { return user.active; } then users.filter(isActive).
Scenario B — accidental always-true. Returning the item itself can work for objects (truthy) but fails for 0 or "". Prefer an explicit boolean test.
A tiny practice file
Save as filter-find.html.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>filter find findIndex</title>
</head>
<body>
<input id="min" type="number" value="7" />
<button id="go">Run</button>
<pre id="out"></pre>
<script>
const scores = [4, 9, 2, 10, 7];
document.getElementById("go").addEventListener("click", function () {
const min = Number(document.getElementById("min").value);
const passing = scores.filter(function (s) {
return s >= min;
});
const first = scores.find(function (s) {
return s >= min;
});
const idx = scores.findIndex(function (s) {
return s >= min;
});
document.getElementById("out").textContent =
"filter: " + JSON.stringify(passing) + "\n" +
"find: " + String(first) + "\n" +
"findIndex: " + idx;
});
</script>
</body>
</html>
Raise the minimum until find becomes undefined and findIndex becomes -1.
Mistakes I see a lot
1. Using filter when you need one item. Prefer find.
2. Not checking undefined after find. Crash on .name.
3. Treating -1 from findIndex as a real index. arr[-1] is not the last item in normal code.
4. Mutating inside filter. Keep the callback a pure test when you can.
5. Comparing with = instead of === in the test. Accidental assignment bugs.
6. Expecting filter to return null when empty. It returns [].
What to try before the next post
filternumbers above 5.findthe first even number; handle missing.findIndexof a string in a tag list; check for-1.- Build the tiny HTML file.
Next in this series: some, every, and includes — yes/no questions about the whole list.
Try this next outside the series
Arrays get easier when you see them render UI lists and move through real transforms.
- React hooks patterns — see arrays, mapping, and derived state inside everyday React code
- JSON Formatter — inspect array payloads from APIs without losing the shape