Back

JavaScriptで配列の最後にマッチする値を取得する方法

JavaScriptで配列の最後にマッチする値を取得する方法

配列内で条件に一致する最後の要素を見つける必要があります。それは最新のエラーログかもしれませんし、最後の有効なフォーム入力、または最後にアクティブだったユーザーかもしれません。ES2023以前は、配列を反転させたり、すべてをフィルタリングしたり、手動でループを書いたりといった不格好な回避策が必要でした。今では、よりクリーンな方法があります。

重要なポイント

  • findLast()を使用すると、元の配列を変更せずに条件に一致する最後の配列要素を取得できます。
  • 値そのものではなく位置が必要な場合は、findLastIndex()を使用します。
  • reverse().find()の使用は避けてください。元の配列を変更し、微妙なバグを引き起こします。
  • 戻り値の違いを覚えておきましょう:findLast()は一致するものがない場合undefinedを返し、findLastIndex()-1を返します。

モダンなソリューション: Array.prototype.findLast()

Array.prototype.findLast()は配列を後方から反復処理し、述語を満たす最初の要素を返します。これは先頭から検索するfind()のミラー版です。

const logs = [
  { type: 'info', message: 'Started' },
  { type: 'error', message: 'Connection failed' },
  { type: 'info', message: 'Retrying' },
  { type: 'error', message: 'Timeout' }
]

const lastError = logs.findLast(log => log.type === 'error')
// { type: 'error', message: 'Timeout' }

要素が一致しない場合、findLast()undefinedを返します。これにより、オプショナルチェーンと安全に使用できます:

const lastError = logs.findLast(log => log.type === 'critical')?.message ?? 'No critical errors'

findLast vs findLastIndex: 位置が必要な場合

値ではなくインデックスが必要な場合もあります。それがfindLastIndex()の役割です。これは最後に一致する要素のインデックスを返し、何も一致しない場合は-1を返します。

const numbers = [1, 5, 3, 8, 2, 9, 4]
const lastLargeIndex = numbers.findLastIndex(n => n > 7)
// 5 (9のインデックス)

その位置から splice や slice を行う必要がある場合、または隣接する要素を参照する必要がある場合は、findLastIndex()を使用してください。

ブラウザ互換性とフォールバック

findLast()findLastIndex()はどちらもES2023の一部であり、モダンブラウザと最近のNode.jsバージョンで広くサポートされています。ただし、古い環境ではこれらが含まれていない場合があります。

TypeScriptがこれらのメソッドについて警告を出す場合、tsconfig.jsonのコンパイラオプションに"lib": ["ES2023"]以降を追加する必要があります。

ネイティブサポートがない環境向けに、元の配列を変更しないクリーンなフォールバックを以下に示します:

function findLast(arr, predicate) {
  for (let i = arr.length - 1; i >= 0; i--) {
    if (predicate(arr[i], i, arr)) {
      return arr[i]
    }
  }
  return undefined
}

この逆方向ループは効率的です。最初の一致で停止し、中間配列の作成を避けます。

避けるべき一般的な落とし穴

find()を使うために配列を反転させないでください:

// ❌ 元の配列を変更してしまう!
const last = arr.reverse().find(x => x > 5)

// ✅ 代わりにfindLastを使用
const last = arr.findLast(x => x > 5)

reverse()を呼び出すと、配列がその場で変更されます。これはデバッグが困難な微妙なバグを引き起こします。

戻り値を混同しないでください:

  • findLast()は要素またはundefinedを返します
  • findLastIndex()はインデックスまたは-1を返します

真偽値のチェックはfindLast()では機能しますが、findLastIndex()では明示的に-1をチェックする必要があります:

const index = arr.findLastIndex(x => x > 100)
if (index !== -1) {
  // 見つかった
}

偽値の一致に注意してください:

配列に0false、または空文字列が含まれている場合、述語が正しく処理することを確認してください:

const values = [1, 2, 0, false, 'last']
values.findLast(x => x)        // 'last' (偽値をスキップ)
values.findLast(() => true)    // 'last' (実際の最後の要素を取得)

それぞれのアプローチを選択するタイミング

必要なものメソッド
条件に一致する最後の要素findLast()
最後に一致する要素のインデックスfindLastIndex()
単純な最後の要素(条件なし)arr.at(-1) または arr[arr.length - 1]
正確な値の検索lastIndexOf()

まとめ

JavaScriptで配列の最後にマッチする値を取得するには、まずfindLast()を使用しましょう。読みやすく、データを変更せず、一致を見つけ次第停止します。値ではなく位置が必要な場合は、findLastIndex()を使用してください。古い環境では、シンプルな逆方向ループがreverse()の変更リスクなしに信頼性の高いフォールバックを提供します。述語を明示的に保ち、undefined-1という異なる戻り値を覚えておくことで、サイレントな失敗を避けることができます。

よくある質問

はい、findLast()は疎な配列で動作します。配列を後方から反復処理し、空のスロットをスキップして、実際に存在する要素に対してのみ述語を呼び出します。この動作は、find()が前方に反復処理する際に疎な配列を処理する方法と同じです。

findLast()は一致を見つけ次第反復を停止するため、より効率的です。filter().pop()を使用すると、最初に配列全体を処理し、メモリに新しい配列を作成してから最後の要素を取得します。大きな配列の場合、findLast()は大幅なパフォーマンス向上を提供します。

はい、findLast()はTypeScriptのジェネリクスと型の絞り込みをサポートしています。述語として型ガードを使用すると、TypeScriptは返される要素の絞り込まれた型を正しく推論します。適切な型定義を得るために、tsconfig.jsonのlib配列にES2023が含まれていることを確認してください。

はい、メソッドが存在しない場合、Array.prototypeにポリフィルを追加できます。最初にメソッドの存在を確認し、配列を後方からループする関数を割り当てます。core-jsやその他のポリフィルライブラリも、より広範な互換性のための既製の実装を提供しています。

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay