lastIndexOf とは何か
lastIndexOf は「配列の中から、指定した値が“最後に現れる位置(インデックス)”を返す」検索メソッドです。見つかれば 0 以上の番号、見つからなければ -1 を返します。ここが重要です:検索は“末尾側から先頭へ向かって”進みますが、返すのは「最後に現れた要素のインデックス」です(配列のインデックス自体は常に先頭基準の 0 始まり)。
基本の使い方と戻り値
最後の出現位置を調べる
const a = ["A", "B", "A", "C"];
const i = a.lastIndexOf("A");
console.log(i); // 2(最後に現れる "A" はインデックス 2)
console.log(a[i]); // "A"
JavaScriptここが重要です:重複があるとき、“最後のもの”を扱いたい場面で便利です。見つからない場合は -1 を返すので、if (i >= 0) で判定するのが定石です。
見つからないときは -1
const a = [1, 2, 3];
const i = a.lastIndexOf(99);
console.log(i); // -1
if (i === -1) {
// 無かったときの処理
}
JavaScriptここが重要です:-1 は“未検出”の明確なシグナル。削除や置き換えの前に必ずチェックします。
厳密比較(===)と型・参照の注意
型が違うと一致しない
const nums = [1, 2, 3, 2];
console.log(nums.lastIndexOf("2")); // -1("2" は文字列、2 は数値)
JavaScriptここが重要です:比較は厳密等価(===)。文字列 “2” と数値 2 は別物です。検索前に型を揃えましょう。
オブジェクト・配列は“同じ参照”だけ一致
const obj = { id: 1 };
const a = [{ id: 1 }, obj, { id: 1 }];
console.log(a.lastIndexOf(obj)); // 1(同じ参照)
console.log(a.lastIndexOf({ id: 1 })); // -1(別インスタンス)
JavaScriptここが重要です:中身が同じでも、別インスタンスは一致しません。プロパティで探したいなら findIndex(または後方探索の自前ループ)を使います。
NaN は見つからない(NaN !== NaN)
console.log([NaN, 1, NaN].lastIndexOf(NaN)); // -1
JavaScriptここが重要です:NaN は自分自身とも等しくありません。存在判定は includes(NaN 対応)や findIndex(Number.isNaN) を使います。
[NaN].includes(NaN); // true
[NaN, 1, NaN].findIndex(Number.isNaN); // 0
JavaScriptfromIndex(開始位置)と負の値の挙動
指定位置から“後ろ向き”に検索する
const a = ["A", "B", "A", "C", "A"];
console.log(a.lastIndexOf("A")); // 4(最後の "A")
console.log(a.lastIndexOf("A", 3)); // 2(インデックス3から後方検索)
JavaScriptここが重要です:fromIndex は「ここから後ろ向きに探す」開始位置。重複の“ひとつ前”を取りたいときは、前回の位置より 1 つ小さい値を指定します。
fromIndex が負の値(末尾からの相対指定)
const a = ["A", "B", "A", "C", "A"];
console.log(a.lastIndexOf("A", -2)); // 2
JavaScriptここが重要です:負の fromIndex は「末尾からの相対位置」(-1 は最後、-2 は最後から2番目)。計算後に 0 未満なら 0 に切り上げられ、結果的に“先頭までしか検索しない”挙動になります。
実践パターン(最後の要素を扱う定番)
最後に現れた値を削除する
const items = ["pen", "book", "note", "book"];
const i = items.lastIndexOf("book");
if (i >= 0) items.splice(i, 1);
console.log(items); // ["pen", "note", "book"]
JavaScriptここが重要です:重複があるとき“最後の1件だけ削除”が簡単に書けます。-1 チェックは必須です。
最後の出現を置き換える
const colors = ["red", "green", "blue", "green"];
const i = colors.lastIndexOf("green");
if (i >= 0) colors[i] = "lime";
console.log(colors); // ["red", "green", "blue", "lime"]
JavaScriptここが重要です:位置さえ分かれば更新は一瞬。存在しない場合の分岐も明確にしましょう。
“最後から順に処理”の制御に使う
const steps = ["load", "render", "render", "cleanup"];
let i = steps.lastIndexOf("render");
while (i >= 0) {
// i の "render" を処理 …
i = steps.lastIndexOf("render", i - 1); // ひとつ前を探す
}
JavaScriptここが重要です:重複を“末尾側から”辿ると、インデックスずれのバグを避けやすくなります。
関連メソッドの使い分け
indexOf と lastIndexOf の違い
- 先頭側から最初を取りたいなら indexOf。
- 末尾側から最後を取りたいなら lastIndexOf。 ここが重要です:どちらも === 比較、-1 が未検出。目的に応じて“どちら側”の発生位置が欲しいかで選びます。
あるかどうかだけなら includes
const a = ["A", "B", NaN];
a.includes("B"); // true
a.includes(NaN); // true(NaN 対応)
JavaScriptここが重要です:位置が不要なら includes のほうが意図が明確で、NaN にも対応します。
条件で探すなら findIndex
const users = [{id:1},{id:2},{id:2}];
const i = users.findIndex(u => u.id === 2); // 1(最初の一致)
JavaScriptここが重要です:プロパティや複合条件で探す場合は findIndex。最後の一致が欲しいなら、後ろ向きループや fromIndex を組み合わせて制御します。
よくある落とし穴と回避策
型違いで一致しないまま -1 を返し、誤って“無い”扱いになることがあります。検索前に型を揃えるか、必要なら文字列→数値の変換を入れてください。NaN は lastIndexOf で見つかりません。存在判定は includes、位置が欲しいなら findIndex(Number.isNaN) を使います。-1 のチェックを忘れて splice すると、末尾付近の誤削除を招きます。必ず if (i >= 0) を条件に。重複を前から順に splice すると、削除でインデックスが詰まり、次の位置がずれるバグが起こります。lastIndexOf を使って“後ろから”処理するか、非破壊の filter に切り替えましょう。
まとめ
lastIndexOf は「指定値が最後に現れる位置」を返すメソッドで、見つからなければ -1。検索は末尾側からで、fromIndex で開始位置を制御でき、負の値は末尾からの相対指定です。比較は厳密等価(===)で、NaN は検出できません。重複の“最後だけ”を削除・置換したいときに最短で安全に書けます。位置が不要なら includes、条件検索なら findIndex を使い分ける。-1 判定と型・参照の性質を押さえれば、初心者でも意図通りの後方検索が確実に書けます。
