🔰

「何にでも .filter() を使う人」にならないために覚えておきたい JavaScript の便利な組み込みメソッド

に公開
3

はじめに

そろそろ新卒一括採用されたエンジニアの研修が終わって配属が始まる時期なので、主に JavaScript 初心者を対象にした記事をひとつ。

初心者に限らず、年次的に中級者くらいでも「何にでも .filter() を使う人」を割とよく見かけるので、もっといい方法があるということをぜひ覚えていってください。

便利な組み込みメソッド

JavaScript の配列 (["apple", "banana", "cherry"] のように、複数の値をリスト形式で持つデータ) には、標準で .sort().map() のようなメソッドが備わっています。

自分で for 文を書くより、間違いなく効率的で分かりやすく、配列に関する処理を書くことができる強力な手段です。例に挙げた以外にも標準で便利な関数が数多く用意されています。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array#:~:text=インスタンスメソッド

引数に関数を渡して呼び出す「高階関数」と呼ばれる関数なので、使い方に慣れるまで少し時間がかかるかもしれませんが、JavaScript を使うなら必ず身に着けておきたいテクニックです。

.filter()

.filter() は、配列から条件に一致する要素だけを抽出する組み込みメソッドです。

filter-example.ts
const numbers = [1, 2, 3, 4, 5];
const oddNumbers = numbers.filter(value => value % 2 === 1);
// oddNumbers: [1, 3, 5]

とても汎用的なメソッドなので覚えておいて損はありません。

しかし、便利なメソッドは .filter() だけではありません!

.find()

.find() は、配列から条件に一致する最初の要素を取り出します。条件に一致する要素がない場合は undefined を返します。

find-example.ts
const users = [
  {id: '0000', name: 'Taro'},
  {id: '0001', name: 'Jiro'},
  {id: '0002', name: 'Saburo'}
];
const user = users.find(user => user.id === '0000');
// user: {id: '0000', name: 'Taro'}

.filter() と似ていますが、 条件に一致する要素が 1 つ見つかった時点で処理を終了する ので、処理に無駄がありません。
.filter() でも同じ処理はできますが、最初に 'Taro' を見つけても処理が終わらず、 'Jiro''Saburo' にも絞り込み処理をしてしまいます。

以下のような書き方をしていませんか?

find-using-filter-example.ts
// よくない例:全ての要素を調べてしまう
const user = users.filter(user => user.id === '0000')[0];

// いい例:条件に一致する最初の要素が見つかった時点で処理を終了
const user = users.find(user => user.id === '0000');

.find() を使うことでパフォーマンス面が改善するだけでなく、「1 つ見つけたい」という目的が明確になり、.filter()[0] と比べて可読性も改善します。

.some()

.some() は、配列の要素のうち 少なくとも1つが条件を満たすかどうか を判定します。条件を満たす要素が1つでも見つかると true を返し、1つも見つからなければ false を返します。

some-example.ts
const numbers = [1, 2, 3, 4, 5];
const hasEvenNumber = numbers.some(num => num % 2 === 0);
// hasEvenNumber: true (2と4が偶数なので)

const users = [
  {name: 'Taro', age: 27},
  {name: 'Jiro', age: 25},
  {name: 'Saburo', age: 22}
];
const hasAdult = users.some(user => user.age >= 18);
// hasAdult: true

条件に一致する要素が1つ見つかった時点で処理を終了する ので効率的です。

以下のような書き方をしていませんか?

some-using-filter-example.ts
// よくない例:全ての要素を調べてしまう
const hasAdult = users.filter(user => user.age >= 18).length > 0;

// 良い例:条件に一致する要素が見つかった時点で終了
const hasAdult = users.some(user => user.age >= 18);

.every()

.every() は、配列の 全ての要素が条件を満たすかどうか を判定します。全ての要素が条件を満たせば true、1つでも満たさない要素があれば false を返します。

every-example.ts
const numbers = [2, 4, 6, 8];
const allEven = numbers.every(num => num % 2 === 0);
// allEven: true (全て偶数なので)

const users = [
  {name: 'Taro', age: 22},
  {name: 'Jiro', age: 20},
  {name: 'Saburo', age: 17}
];
const allAdults = users.every(user => user.age >= 18);
// allAdults: false (Saburo が 17 歳で未成年なので)

条件を満たさない要素が1つ見つかった時点で処理を終了する ので、こちらも効率的です。

以下のような書き方をしていませんか?

every-using-filter-example.ts
// よくない例:全ての要素を調べてフィルタリングする
const allAdults = users.filter(user => user.age >= 18).length === users.length;

// 良い例:条件を満たさない要素が見つかった時点で終了
const allAdults = users.every(user => user.age >= 18);

まとめ

メソッド 用途 戻り値 早期終了
.filter() 条件に一致する要素を全て抽出 配列 なし
.find() 条件に一致する最初の要素を取得 要素 or undefined あり
.some() 条件に一致する要素が1つでもあるか判定 boolean あり
.every() 全ての要素が条件に一致するか判定 boolean あり

おわりに

配列操作では、目的に応じて適切なメソッドを選択することで、コードの可読性とパフォーマンスの両方を向上させることができます。

特に大きな配列を扱う場合、早期終了する .find().some().every() を適切に使い分けることで、無駄な処理を削減できます。

最初は慣れないかもしれませんが、これらのメソッドを使いこなせるようになると、より美しく効率的なJavaScriptコードを書けるようになります。ぜひ積極的に活用してみてください!

さらに効率よくコードを書きたい

標準メソッドにはない unique()groupBy() のような汎用的な関数を提供するユーティリティライブラリを導入すると、さらに可読性の高いコードを書くことができます。
型安全でサイズが小さく計算効率の良い Remeda がお勧めです!

https://zenn.dev/kiyoshiro9446/articles/utility-remeda

Discussion

junerjuner

配列として処理するのではなくイテレータとして処理させる為の .values() とかも便利ですよね。(配列の生成回数が減らせますので

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/values

イテレータだと標準メソッドとして 列挙する件数を制限する .take() や スキップする .drop() 配列を生成する .toArray() なども含まれています

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Iterator