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 inside for just to keep some rows
  • Beginners who use filter when they only needed one item
  • Anyone who checks find results without handling undefined

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

NeedUse
Many matches as a listfilter
First matching valuefind
First matching indexfindIndex
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

  1. filter numbers above 5.
  2. find the first even number; handle missing.
  3. findIndex of a string in a tag list; check for -1.
  4. 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.