find と includes で配列を検索する
find と includes で配列を検索する とは
Array.prototype.find / findIndex / includes を使って、条件に合う要素や存在判定を簡潔に書く。
find と includes で配列を検索する
配列の中から「条件に合う要素」を探したい場面は日常茶飯事です。古典的には for ループを回して if で判定するわけですが、現代の JavaScript にはもっと宣言的な書き方が用意されています。find、findIndex、includes、indexOf の 4 つを使い分けられれば、検索コードはぐっと短く読みやすくなります。
検索は 「何を返したいか」 で API を選ぶ。値そのものなら
find、位置ならfindIndex、有無だけならincludes。
find は条件に合う最初の要素を返す
Array.prototype.find は、コールバックが true を返した最初の要素を返します。見つからなければ undefined です。
JavaScript
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Carol" },
];
const found = users.find((u) => u.id === 2);
console.log(found); // { id: 2, name: "Bob" }コールバックは要素ごとに呼ばれ、true を返した瞬間に走査が止まります。全部見て回らないので大きな配列でも効率的です。
findIndex は位置を返す
要素そのものではなく位置 (インデックス) が欲しいときは findIndex を使います。見つからなければ -1 を返します。
JavaScript
const idx = users.findIndex((u) => u.name === "Carol");
console.log(idx); // 2
const notFound = users.findIndex((u) => u.name === "Zoe");
console.log(notFound); // -1見つからなかった時の戻り値は
findがundefined、findIndexが-1。これを忘れるとif判定でバグる。
includes は有無だけを boolean で返す
「ある値が配列に含まれているか?」だけ知りたいときは includes です。コールバックは渡さず、検索したい値を直接渡します。
JavaScript
const tags = ["js", "react", "node"];
console.log(tags.includes("react")); // true
console.log(tags.includes("vue")); // falseindexOf も似た用途で使えますが、includes の方が真偽値で読みやすく、NaN の比較も正しく扱えます ([NaN].indexOf(NaN) は -1、[NaN].includes(NaN) は true)。
動きを追ってみる
図のとおり、find は要素を 1 つずつ調べ、最初に true を返した要素で走査を打ち切ります。見つからずに末尾まで到達したら undefined です。
filter との違い
似た名前の filter は、条件に合う全要素を配列で返します。find は最初の 1 つだけです。
JavaScript
const nums = [1, 2, 3, 4, 5];
nums.find((n) => n > 2); // 3
nums.filter((n) => n > 2); // [3, 4, 5]用途で選びましょう。1 件取りたければ find、複数取りたければ filter です。
よくある間違い
第 1 に、find の結果をそのままプロパティアクセスすると、見つからなかったときに Cannot read properties of undefined で落ちます。オプショナルチェーン ?. やデフォルト値で対策します。第 2 に、findIndex の戻り値を if (idx) で判定すると idx === 0 も false 扱いになります。必ず if (idx !== -1) で書きます。第 3 に、includes はオブジェクトに対しては参照一致でしか動きません。同じ形でも別オブジェクトなら false です。
findで見つからなかったらどうするか、必ず早めに設計する。?.や??と組み合わせるのが定番。
やってみよう
配列 arr と検索値 target を受け取り、target が存在すればそのインデックス、無ければ -1 を返す indexOfValue 関数を書きましょう。return arr.findIndex((v) => v === target) の 1 行で完成です。代わりに arr.indexOf(target) でも同じ動作になりますが、ここでは findIndex の使い方に慣れることが目的です。includes で true/false を返すバリエーションも書いてみてください。
よくある質問
Q. ブラウザと Node.js で動作は変わりますか?
A. JavaScript の構文・組み込み機能(配列・文字列・Promise 等)はどちらでも同じです。違いは DOM API(ブラウザ専用)と fs などのファイル系(Node 専用)など、実行環境固有の機能です。コアロジックは両方で動くため、テストもしやすくなります。
Q. ES6 以降の新機能は使っても大丈夫ですか?
A. 現代のブラウザ・Node.js は ES2020 以降の機能をほぼサポートしています。古い IE 等を対象にする必要が無ければ、let/const、アロー関数、分割代入、async/await を積極的に使ってください。トランスパイル(Babel/Vite)が必要なケースは年々減っています。
Q. TypeScript に進む価値はありますか?
A. 型情報があるとリファクタやエディタ補完が劇的に効くため、規模が大きくなるなら TypeScript への移行を強くおすすめします。最初は any を許容しつつ徐々に型を付ければ、JS の知識をそのまま活かせます。
次のレッスン
次は 数値配列を昇順にソートする で、Array を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- find と includes の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. find と includes とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- Array.prototype.findIndex を使うこと
- 見つからないときは -1 を返すこと
===で厳密一致を判定すること
入出力例
test-cases.txt
indexOfValue([10,20,30,40], 30) → 2
indexOfValue([5,6,7], 5) → 0
indexOfValue([1,2,3], 99) → -1
indexOfValue([], 1) → -1