findIndex とは何か
findIndex は「配列の中から、条件に一致する“最初の1要素のインデックス(位置)”を返す」検索メソッドです。見つかれば 0 以上の番号、見つからなければ -1 を返します。ここが重要です:findIndex は“値そのものの一致”ではなく、“関数で定義した条件”で探します。オブジェクトのプロパティ一致や複合条件など、indexOf では表現しづらい検索に向いています。
基本の使い方(コールバックで条件を定義)
最初に一致した“位置”を取得する
const users = [
{ id: 1, name: "A" },
{ id: 2, name: "B" },
{ id: 3, name: "B" }
];
const i = users.findIndex(u => u.name === "B");
console.log(i); // 1(最初に一致したのはインデックス1)
console.log(users[i]); // { id: 2, name: "B" }
JavaScriptここが重要です:返るのは“要素そのもの”ではなく“位置”。要素が欲しいなら users[i] と組み合わせるか、最初から find を使います。
見つからない場合は -1(安全な判定を徹底)
const xs = [10, 20, 30];
const i = xs.findIndex(x => x > 100);
console.log(i); // -1(条件に合う要素が無い)
if (i >= 0) {
// 見つかったときの処理
} else {
// 無かったときの処理(追加・スキップなど)
}
JavaScriptここが重要です:-1 のまま splice(i, 1) などをすると末尾付近の誤削除につながります。必ず i >= 0 を条件に使います。
コールバックの引数と thisArg
value・index・array の3つが渡される
const arr = [5, 12, 8];
const i = arr.findIndex((value, index, array) => {
// value: 今見ている値
// index: 現在の位置
// array: 元の配列(必要なら参照)
return value % 4 === 0 && index > 0;
});
console.log(i); // 2(8 の位置)
JavaScriptここが重要です:位置条件や配列全体に基づく判定を、1つの関数で自然に書けます。
thisArg でコールバック内の this を指定できる
const cfg = { limit: 50 };
const arr = [10, 60, 40];
const i = arr.findIndex(function (x) { return x > this.limit; }, cfg);
console.log(i); // 1
JavaScriptここが重要です:通常は外部変数を直接参照(クロージャ)で十分ですが、必要なら thisArg を使って文脈を渡せます。
indexOf/find/includes との使い分け
値そのものの一致なら indexOf/includes
indexOf は“値そのもの”が一致する最初の位置、includes は“存在するか”だけを返します。プロパティ一致や範囲・複合条件の検索は findIndex(または find)が適切です。
要素が欲しいなら find、位置が欲しいなら findIndex
const users = [{id:1},{id:2}];
const i = users.findIndex(u => u.id === 2); // 1
const user = users.find(u => u.id === 2); // {id:2}
JavaScriptここが重要です:更新・削除など“位置ベースの操作(a[i] = … / splice(i, 1))”には findIndex が最短です。要素の値だけが必要なら find を選びます。
実践パターン(更新・削除・挿入)
見つけた要素を更新する
const users = [{id:1,name:"A"}, {id:2,name:"B"}];
const i = users.findIndex(u => u.id === 2);
if (i >= 0) {
users[i] = { ...users[i], name: "B2" }; // 非破壊的に要素を差し替え
}
JavaScriptここが重要です:直接プロパティを書き換えるより、スプレッドで新オブジェクトに置き換えるほうが副作用が少なく安全です。
見つけた要素を削除する
const items = ["pen", "book", "note"];
const i = items.findIndex(x => x === "book");
if (i >= 0) items.splice(i, 1);
JavaScriptここが重要です:i >= 0 の確認を必ず行います。削除後はインデックスが詰まるため、複数削除は“後ろから”処理するか、非破壊の filter に切り替えます。
条件位置へ挿入(前に差し込む)
const users = [{id:1},{id:3}];
const i = users.findIndex(u => u.id === 3);
if (i >= 0) users.splice(i, 0, { id: 2 }); // 3 の直前に挿入
JavaScriptここが重要です:findIndex で“挿入地点”を確定してから splice。位置が明確なのでバグが減ります。
パフォーマンスと挙動の要点
最初に見つかったら即停止(短絡評価)
findIndex は先頭から順に評価し、条件を満たした瞬間に探索を止めます。ここが重要です:重い判定ロジックでは、前段に軽いチェックを置いて無駄な評価を減らすと効率が上がります。
非破壊(配列は変更しない)
findIndex 自体は配列を変更しません。ここが重要です:更新・削除を続けて行う場合は、その操作が破壊的か非破壊か(splice は破壊的、slice+スプレッドは非破壊)を意識して選びます。
よくある落とし穴と回避策
-1 チェックを忘れる
-1 のまま array[-1] にアクセスすると未定義、splice(-1, 1) は末尾削除になります。必ず i >= 0 を条件にしてください。
見つけた要素を直接書き換えて副作用
オブジェクト要素をそのまま編集すると、共有参照に影響します。UIの差分検知が必要なら、 { ...obj, key: newValue } のように新オブジェクトで置換するか、配列全体を map で非破壊更新しましょう。
複数削除でインデックスがずれる
前から順に splice を繰り返すと、削除のたびにインデックスが詰まって次の位置が変わります。後ろから処理する、または filter で非破壊に複数条件削除を行うと安全です。
まとめ
findIndex は「条件に一致する最初の“位置”を返す」検索メソッドで、見つからなければ -1。値そのものの一致は indexOf/includes、要素が欲しいなら find。更新・削除・挿入の“位置ベース操作”で威力を発揮します。-1 判定の徹底、破壊・非破壊の選択、共有参照への配慮(要素のスプレッド置換)を押さえれば、初心者でも安全で意図通りの検索・編集ロジックを短く書けます。
