JavaScript

JavaScriptのfindLast():配列の末尾から条件に合う1件を取得する

この記事でわかること

Array.prototype.findLast()で配列の末尾から条件に合う要素を探す方法を解説。引数・戻り値、ブラウザーとNode.jsの実行手順、履歴検索の実例と非同期処理の注意点を学べます。

目的:履歴を後ろから探す

操作履歴や処理結果を配列へ順番に追加していると、「最後に成功した処理」を取り出したくなることがあります。そこで使えるのがArray.prototype.findLast()です。末尾から先頭へ条件を調べ、一致した要素を1つ返します。

たとえば成功・失敗が混ざる実行履歴から成功した記録を探す場合、最後の要素を読むだけでは足りません。末尾が失敗なら、その前へさかのぼる必要があります。findLast()なら、この検索の意図を短く表現できます。

条件に一致すると、その時点で検索を終了します。すべての一致要素を集める必要がない用途に適しています。検索方向と終了条件はMDNの公式リファレンスで確認できます。

動作環境と対応バージョン

確認日は2026年11月6日です。findLast()はブラウザーとNode.jsの両方で利用できます。DOMに依存しないため、本記事のJavaScriptコードは同じ内容で実行できます。

MDNでは、主要ブラウザーで2022年8月以降利用可能な機能として案内されています。古いブラウザーや組み込みWebViewでは、利用前に次のように存在を確認してください。

JavaScript
console.log(typeof Array.prototype.findLast === "function");

対応環境ではtrue、未対応環境ではfalseになります。未対応のまま呼び出すと、通常はTypeErrorになります。

Node.jsでは18.0.0で導入されました。これは機能の導入バージョンであり、現在利用するバージョンの推奨ではありません。新しく環境を用意する場合は、サポート中のLTS版を利用してください。導入の根拠はNode.js 18.0.0の公式リリースノートにあるV8更新の記述です。

引数と戻り値

基本形は次のとおりです。

JavaScript
array.findLast(callbackFn, thisArg);
  • callbackFnは必須の判定関数です。条件に合うときにtrueを返すように書くと意図が明確です。
  • 判定関数には、現在の要素element、その添字index、検索対象の配列arrayが渡されます。
  • thisArgは省略可能で、通常の関数で書いた判定関数のthisに使う値です。アロー関数のthisは変更できません。

判定結果は真偽値へ変換して評価されます。戻り値は一致した要素そのものであり、配列や添字ではありません。一致がなければundefinedです。空配列でもundefinedを返します。

「最後」は配列の位置を意味する

ここでいう最後とは、条件に合う要素のうち添字が最も大きいものです。日時を比較して最新の要素を選ぶ処理ではありません。

履歴を古い順に追加しているなら、末尾側ほど新しいという前提が成立します。一方、APIから受け取ったデータの並び順が保証されない場合、そのまま使っても最新の記録は選べません。先にデータの順序を確認することが必要です。

自己完結したコードで履歴を検索する

次の例では、履歴からstatusがsuccessの記録を探します。外部通信や追加ライブラリーは使いません。全体をコピーして実行できます。

JavaScript
(() => {
  "use strict";

  if (typeof Array.prototype.findLast !== "function") {
    console.log("この環境はfindLast()に未対応です");
    return;
  }

  const history = [
    { id: "job-a", status: "success", count: 12 },
    { id: "job-b", status: "failed", count: 0 },
    { id: "job-c", status: "success", count: 8 },
    { id: "job-d", status: "failed", count: 0 }
  ];

  const visited = [];
  const latestSuccess = history.findLast((entry, index) => {
    visited.push(index);
    return entry.status === "success";
  });

  if (latestSuccess === undefined) {
    console.log("成功した記録はありません");
  } else {
    console.log(`対象: ${latestSuccess.id}`);
    console.log(`処理件数: ${latestSuccess.count}`);
    console.log(`同じ参照: ${latestSuccess === history[2]}`);
  }

  console.log(`調べた添字: ${visited.join(", ")}`);
  console.log(`元の並び: ${history.map((entry) => entry.id).join(", ")}`);

  const pending = history.findLast((entry) => entry.status === "pending");
  console.log(`待機中: ${pending === undefined ? "なし" : pending.id}`);
})();

ブラウザーでの実行方法

対応ブラウザーで空のタブを開き、開発者ツールのConsoleを表示します。上のJavaScriptコード全体を貼り付けて実行してください。HTMLファイルや開発サーバーは不要です。

全体を即時実行関数で囲んでいるため、もう一度実行しても同名のconst宣言がConsoleのトップレベルに残る問題を避けられます。

Node.jsでの実行方法

上のコードをUTF-8でfind-last-demo.cjsに保存します。ターミナルで保存先のディレクトリーへ移動し、次のコマンドを実行してください。

Shell
node --version
node find-last-demo.cjs

node --versionで使用中のバージョンを確認できます。コードにimportはなく、package.jsonの設定も不要です。

期待出力

対応環境では、コードの評価順から次の出力が期待されます。本記事ではコードの実行は行っていません。

CODE
対象: job-c
処理件数: 8
同じ参照: true
調べた添字: 3, 2
元の並び: job-a, job-b, job-c, job-d
待機中: なし

添字3のjob-dは条件に合わず、添字2のjob-cで一致して終了します。元の配列を反転させる操作は行っていないため、並び順も保たれます。

失敗例と制約

見つからない場合にプロパティを読まない

検索結果が常に存在するとは限りません。次のコードはundefinedのプロパティを読もうとして例外になります。

JavaScript
const records = [{ status: "failed" }];

try {
  const result = records.findLast((record) => record.status === "success");
  console.log(result.status);
} catch (error) {
  console.log(error.name);
}

対応環境での期待出力はTypeErrorです。主要例のようにresult === undefinedを確認してからプロパティを参照してください。また、判定関数自身が例外を投げた場合も、検索は中断されて呼び出し元へ伝わります。

要素としてundefinedを保存できる配列では、戻り値だけで「未発見」と「その値を発見」を区別できません。検索対象のデータ設計も確認しましょう。

非同期の判定関数を渡さない

次は意図どおりに判定できない例です。

JavaScript
const jobs = [
  { id: "a", ready: true },
  { id: "b", ready: false }
];

const wrong = jobs.findLast(async (job) => job.ready);
console.log(wrong.id);

期待出力はbです。async関数はPromiseを返し、Promiseオブジェクト自体は真として評価されるため、末尾の要素が選ばれます。これは、戻り値を真偽として評価する仕様から導かれる挙動です。

通信結果による判定が必要なら、先に結果を取得して通常の値へそろえるか、末尾から回すループの中でawaitしてください。findLast()の結果にawaitを付けても、判定関数を待つ動作には変わりません。

空き要素と参照共有に注意する

疎な配列の空き要素も判定対象になり、値はundefinedとして扱われます。したがって、空き要素があり得る配列で無条件にentry.statusを読むと例外になり得ます。この扱いもMDNの仕様説明に記載されています。

また、見つかったオブジェクトはコピーではありません。主要例のlatestSuccessとhistory[2]は同じオブジェクトです。取得後にプロパティを書き換えると、元の配列から見える値も変わります。

検索中の判定関数では、配列や要素の変更を避けると挙動を追いやすくなります。検索そのものと更新処理を分ける設計が実務では扱いやすいでしょう。

活用事例と導入時の判断

findLast()は、末尾側の一致を1件だけ必要とする場面に向いています。

  • 追加順が保証されたジョブ履歴から、最後の成功記録を選ぶ。
  • 操作ログから、特定ユーザーが最後に行った操作を取り出す。
  • 古い順に並んだ通知から、最後の未読通知を選ぶ。

採用する理由は、配列の順序を保ちながら検索方向を明示できることです。ただし、最悪の場合は配列全体を調べます。巨大な履歴を同じ条件で何度も検索するなら、記録を追加するときに該当する最後の要素も保持する方法を検討できます。

導入時は、まず「後ろほど新しいという前提があるか」「未発見を処理しているか」「判定が同期処理か」を確認してください。この3点が満たされれば、履歴検索を読みやすくまとめられます。

公式参考資料

MDN:Array.prototype.findLast()では、引数、戻り値、末尾からの検索、空き要素の扱い、互換性を確認できます。

Node.js 18.0.0リリースノートでは、V8 10.1への更新に伴うfindLast()の導入を確認できます。

PREFERRED SOURCES

Googleの優先するニュース提供元にSEの部屋を追加

Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。

Googleの設定画面で確認する 新しいタブで開きます

候補にSEの部屋が表示されない場合は、まだ追加できません。

y.
WRITTEN BY

y_ymo10

SEの部屋で、HTML・CSSからJavaScript・React・Next.jsまで、Web制作の開発ノートを公開しています。

ほかの開発ノートを読む →