JavaScript配列のインデックス取得(findIndex)の基本と実践
「条件に合う要素が配列のどこにあるか」を知りたいなら findIndex。見つかった最初の位置(インデックス)を返し、見つからなければ -1。インデックスが分かれば、更新・削除・挿入などの操作に一気に応用できます。
構文と考え方
const index = arr.findIndex((value, index, array) => {
// 条件式(true/false)を返す
return /* 条件式 */;
});
JavaScript- 返り値: 条件に合う「最初の要素のインデックス」。見つからなければ
-1。 - 引数: コールバックには最大3つ(value, index, array)が渡される。ログやデバッグ、複合条件に便利。
- 特徴: 最初の一致で検索終了。複数一致があっても、返るのは先頭の1件の位置。
すぐ使えるテンプレート集
基本:id が 3 の要素のインデックスを取得
const items = [
{ id: 1, name: "Pen" },
{ id: 2, name: "Note" },
{ id: 3, name: "Bag" },
{ id: 3, name: "Shoes" },
];
const i = items.findIndex(x => x.id === 3);
console.log(i); // 2(最初の {id:3} の位置)
JavaScript- ポイント: 2つ目以降の一致は無視される。最初の一致だけ。
見つからない場合の安全な扱い
const nums = [1, 2, 3];
const i = nums.findIndex(n => n > 10);
if (i === -1) {
console.log("見つかりませんでした");
} else {
console.log("位置:", i, "値:", nums[i]);
}
JavaScript- ポイント: -1 チェックは必須。-1 をそのまま参照すると最後の要素を誤って触るコードが出がち。
見つかった位置の要素を更新
const products = [
{ id: 1, price: 120 },
{ id: 2, price: 300 },
{ id: 3, price: 450 },
];
const i = products.findIndex(p => p.id === 2);
if (i !== -1) {
products[i] = { ...products[i], price: 330 }; // 値上げ
}
console.log(products);
JavaScript- ポイント: スプレッドで安全に「上書き」。不変性を保ちたい場合は新配列を作る。
見つかった位置の要素を削除(splice)
const cart = [
{ id: 1, name: "Pen" },
{ id: 2, name: "Note" },
{ id: 3, name: "Bag" },
];
const i = cart.findIndex(x => x.id === 2);
if (i !== -1) {
cart.splice(i, 1); // その位置から1件削除
}
console.log(cart);
JavaScript- ポイント: splice は元配列を変更する(破壊的)。不変にしたいなら filter を使って新配列を作る。
見つかった位置の前に挿入
const arr = ["A", "B", "D"];
const i = arr.findIndex(x => x === "D");
if (i !== -1) {
arr.splice(i, 0, "C"); // D の前に C を挿入
}
console.log(arr); // ["A", "B", "C", "D"]
JavaScript- ポイント: splice の第2引数が 0 なら「削除なしで挿入」。
よくある落とし穴と対策
- -1 チェック忘れ
- 症状: 見つからないのに
arr[-1]を参照し、思わぬバグに。 - 対策: 必ず
if (i === -1) return;などで早期リターン。
- 症状: 見つからないのに
- 破壊的操作の乱用
- 症状: splice や直接代入で元配列が書き換わり、他所のコードに影響。
- 対策: 不変にしたいなら、コピーしてから操作(例:slice、スプレッド、filter、map)。
- 複数一致を想定している
- 症状: 最初の1件しか扱えていない。
- 対策: 全件必要なら
filterを使う。findIndex は「最初の位置」専用。
現場で効くパターン集
不変で「更新した新配列」を返す
function updateById(items, id, patch) {
const i = items.findIndex(x => x.id === id);
if (i === -1) return items; // 変更なしで返す
return [
...items.slice(0, i),
{ ...items[i], ...patch },
...items.slice(i + 1),
];
}
JavaScript- ポイント: 元配列を壊さず差し替え。UIフレームワークで差分検出しやすい。
不変で「削除した新配列」を返す
function removeById(items, id) {
const i = items.findIndex(x => x.id === id);
if (i === -1) return items;
return [...items.slice(0, i), ...items.slice(i + 1)];
}
JavaScript- ポイント: filter の方が読みやすい場合もあるが、findIndex は「位置指定」が明確。
条件に応じて「前後に挿入」
function insertBefore(items, predicate, value) {
const i = items.findIndex(predicate);
if (i === -1) return items;
return [...items.slice(0, i), value, ...items.slice(i)];
}
JavaScript- ポイント: predicate を渡せるようにすると再利用性が上がる。
練習問題(手を動かして覚える)
1. 最初の偶数のインデックスを取得
const nums = [3, 7, 11, 12, 5];
const i = nums.findIndex(n => n % 2 === 0);
console.log(i); // 3
console.log(nums[i]); // 12
JavaScript2. id=3 の商品を 10% 値引き(不変で返す)
const products = [
{ id: 1, price: 120 },
{ id: 2, price: 300 },
{ id: 3, price: 450 },
];
const i = products.findIndex(p => p.id === 3);
const discounted =
i === -1
? products
: [
...products.slice(0, i),
{ ...products[i], price: Math.round(products[i].price * 0.9) },
...products.slice(i + 1),
];
console.log(discounted);
JavaScript3. 指定文字の直前に別文字を挿入
const chars = ["a", "b", "d"];
const i = chars.findIndex(c => c === "d");
const result = i === -1 ? chars : [...chars.slice(0, i), "c", ...chars.slice(i)];
console.log(result); // ["a", "b", "c", "d"]
JavaScript直感的な指針
- 位置が欲しいなら: findIndex。値が欲しいなら find。
- 全件を扱いたいなら: filter。
- 更新・削除・挿入と相性抜群: 見つけてから splice(破壊)か不変のスライス構築で処理する。
