JavaScript | 配列・オブジェクト:配列の検索・判定 – lastIndexOf

JavaScript JavaScript
スポンサーリンク

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
JavaScript

fromIndex(開始位置)と負の値の挙動

指定位置から“後ろ向き”に検索する

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 判定と型・参照の性質を押さえれば、初心者でも意図通りの後方検索が確実に書けます。

タイトルとURLをコピーしました