indexOf とは何か
indexOf は「配列の中から、指定した値が最初に現れる位置(インデックス)を返す」検索メソッドです。見つかれば 0 以上の番号、見つからなければ -1 を返します。ここが重要です:indexOf の比較は厳密等価(===)。型が違えば一致しませんし、オブジェクトは“同じ参照”でない限り一致しません。
基本の使い方と戻り値
見つかったときの挙動
const a = ["pen", "book", "note"];
const i = a.indexOf("book");
console.log(i); // 1(0始まり)
console.log(a[i]); // "book"
JavaScriptここが重要です:返ってきたインデックスをそのまま使って要素を参照できます。0 始まりなので、1 は“2番目”の意味です。
見つからないとき(-1 の扱い)
const a = ["pen", "book", "note"];
const i = a.indexOf("pencil");
console.log(i); // -1(未検出)
if (i === -1) {
// 見つからなかったときの処理
}
JavaScriptここが重要です:-1 は「無い」という明確なシグナル。if (i >= 0) で“見つかった”と判定するのが定石です。
厳密比較と型・参照の注意
型が違うと一致しない(===)
const nums = [1, 2, 3];
console.log(nums.indexOf("2")); // -1("2" は文字列、2 は数値)
JavaScriptここが重要です:indexOf は型も比較します。文字列 “2” と数値 2 は別物です。期待する型で検索しましょう。
オブジェクト・配列は“同じ参照”だけ一致
const obj = { id: 1 };
const a = [obj, { id: 1 }];
console.log(a.indexOf(obj)); // 0(同じ参照)
console.log(a.indexOf({ id: 1 })); // -1(別インスタンス)
JavaScriptここが重要です:中身が同じでも別インスタンスは一致しません。プロパティで探したいときは findIndex を使います。
NaN は見つからない(NaN !== NaN)
console.log([NaN].indexOf(NaN)); // -1
JavaScriptここが重要です:NaN は自分自身とも等しくないため、indexOf では検出できません。必要なら includes(NaN を見つけられる)や findIndex と Number.isNaN を使います。
[NaN].includes(NaN); // true
[NaN].findIndex(Number.isNaN); // 0
JavaScript開始位置 fromIndex と負の値
fromIndex で検索の開始位置を指定
const a = ["A", "B", "A", "C"];
console.log(a.indexOf("A")); // 0(最初)
console.log(a.indexOf("A", 1)); // 2(インデックス1から検索)
JavaScriptここが重要です:同じ値が複数あるとき、“次を探す”のに有効です。前回の位置+1 を開始位置にすると連続検索ができます。
fromIndex が負の値(末尾からの相対開始)
const a = ["A", "B", "A", "C"];
console.log(a.indexOf("A", -2)); // 2(最後から2の位置=インデックス2から検索)
JavaScriptここが重要です:負の fromIndex は「末尾からの相対位置」。計算後 0 未満になれば 0 に切り上げられます(つまり“先頭から”検索になります)。
関連メソッドの使い分け
includes(あるかどうかだけ知りたい)
const a = ["pen", "book"];
a.includes("book"); // true(位置は不要、存在判定が目的ならこちら)
JavaScriptここが重要です:位置が不要なら includes のほうが意図が明確で、NaN にも対応します。
lastIndexOf(最後に現れる位置)
const a = ["A", "B", "A"];
console.log(a.lastIndexOf("A")); // 2(末尾側からの最初=“最後の位置”)
JavaScriptここが重要です:重複があり“最後の発生位置”を取りたいときに使えます。
findIndex(条件で探す)
const users = [{id:1},{id:2}];
const i = users.findIndex(u => u.id === 2); // 1
JavaScriptここが重要です:プロパティや複合条件で探したいなら findIndex。indexOf は“値そのもの”が一致する場合に使います。
実践例(削除・置き換え・重複対策)
指定の値を削除する(見つけてから splice)
const items = ["pen", "book", "note"];
const i = items.indexOf("book");
if (i >= 0) items.splice(i, 1);
console.log(items); // ["pen", "note"]
JavaScriptここが重要です:必ず位置を確認してから削除。-1 のまま splice すると末尾付近の意図しない削除になります。
指定の値を別の値に置き換える
const colors = ["red", "green", "blue"];
const i = colors.indexOf("green");
if (i >= 0) colors[i] = "lime";
JavaScriptここが重要です:位置さえ分かれば更新は簡単。存在しなければ追加するなど、分岐で意図を明確にしましょう。
存在判定して重複追加を防ぐ
const tags = ["js", "web"];
const next = tags.includes("ux") ? tags : [...tags, "ux"];
JavaScriptここが重要です:位置が不要なら includes で十分。非破壊で追加する習慣を持つと副作用を避けられます。
よくある落とし穴と回避策
- 型違いの比較ミス: “2” と 2 は一致しません。検索前に型を確認・揃えましょう。
- オブジェクト比較の誤解: 内容が同じでも別インスタンスは一致しません。条件検索は findIndex を使います。
- NaN が見つからない: indexOf は NaN を検出できません。includes や findIndex(Number.isNaN) を使います。
- -1 の扱いミスで誤削除: -1 のまま splice すると末尾付近を削る事故に。必ず i >= 0 を条件にします.
- 重複に対して indexOf をループで乱用: すべての重複を消したいなら filter のほうが簡潔です。
const xs = ["A","B","A"]; const withoutA = xs.filter(x => x !== "A"); // ["B"]
まとめ
indexOf は「値そのものを厳密等価で比較して、最初の位置を返す」メソッドです。見つからなければ -1、開始位置は fromIndex で指定可、負の値は末尾からの相対。型違い・参照比較・NaN という“比較のクセ”を理解し、位置が不要なら includes、条件検索なら findIndex、最後の位置なら lastIndexOf を使い分けましょう。削除や置換では“位置確認してから操作”を徹底すれば、初心者でも安全で意図通りの検索・判定が書けます。
