読み込み中...

JavaScriptのfilter関数で条件を満たす要素を取り出す使い方14選

JavaScriptのfilter関数で配列から条件を満たす要素を抽出する JS
この記事は約30分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

配列から条件に合う値だけを取り出す処理では、Array.prototype.filter()を使うと、元の配列を壊さずに新しい配列を作れます。そのため、検索結果の生成、一覧の絞り込み、入力値の除外、オブジェクト配列の抽出まで、同じ考え方で処理を整理できます。

公式ドキュメントによれば、filter()はコールバック関数が真と評価した要素だけを集めますし、ここがポイントです。詳しい仕様はMDNのArray.prototype.filter()と、配列全体の仕様を確認できるMDNのArrayが一次情報として参考になります。

動作確認環境
  • ECMAScript 2024相当の構文
  • Google Chrome 126以降、Firefox 127以降、Node.js 22系を想定
📖 この記事で学べること
  • filter()の基本構文と戻り値の考え方
  • &&||!==を使った複数条件の書き方
  • 連想配列とオブジェクト配列を絞り込む実用的な使い方
  • アロー関数で条件式を短く保つ書き方
  • 未定義値、部分一致検索、重複排除でつまずきやすい点
用途主な構文返り値注意点
偶数だけ抽出num % 2 === 0条件に合う数値配列===で真偽値を明確にします
複数条件&& / ||条件式が真の要素括弧で評価順を読みやすくします
連想配列Object.entries()キーと値の組Object.fromEntries()で戻せます
オブジェクト配列user.age該当オブジェクト配列存在しないプロパティに注意します
部分一致includes()文字列を含む要素toLowerCase()で表記ゆれを抑えます
正規表現検索new RegExp()パターン一致の要素入力値のエスケープを検討します
変換との連携filter().map()抽出後に変換した配列処理順で読みやすさが変わります
重複排除new Set()一意な値の配列単純値向けの方法です

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

filter関数とは?

filterは、JavaScriptの配列から条件に合う要素だけを残すためのメソッドです。元の配列を直接変更せず、条件を満たした要素だけで構成される新しい配列を返すため、一覧表示や検索結果の生成で扱いやすい形になります。

その性質は、push()で別配列へ手作業で詰め替える処理より読み取りやすくなります。ただし、filter()に渡す関数は真偽値として評価される値を返す必要があり、返り値の型を意識しないと意図しない抽出になるかもしれません。

一般に、配列の加工はforEach・mapの使い分けと一緒に整理すると理解しやすくなるのが基本です。forEach()は繰り返し処理、map()は変換、filter()は絞り込みと覚えると、使い方の判断がぶれにくくなります。

filter関数の基本的な使い方

これが基本構文です。callbackには各要素を判定する関数を渡し、必要に応じてelementindexarrayを受け取ります。

const newArray = array.filter(callback(element[, index[, array]])[, thisArg])

結果: 期待される形として、条件に合う要素だけを含むnewArrayが返りますが、これは押さえたい点です。

このときthisArgは、通常のfunction内でthisとして参照したい値を渡すための引数です。一方、アロー関数は独自のthisを持たないため、thisArgを前提にする処理とは相性を確認する必要があります。

ただし、基本構文を覚えるだけでは、配列処理の判断は安定しません。抽出したいのか、変換したいのか、単に繰り返したいのかを先に決めると、filter()map()forEach()の役割を混同しにくくなります。

サンプルコード1:配列から特定の条件を満たす要素を抽出する

具体的には、数値配列から偶数だけを取り出す処理が最小例になるのが目安です。%で剰余を求め、===で0かどうかを判定します。

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const evenNumbers = numbers.filter(function(num) { return num % 2 === 0; }); console.log(evenNumbers);

結果: 期待される出力は、偶数だけを含む配列になります。

[2, 4, 6, 8, 10]

結果: 期待される出力例として、246810が残りますし、これが一つの目安です。

このコードでは、numbersの各値がnumとしてコールバックへ渡されます。その値が偶数ならtrue相当になり、奇数ならfalse相当になるため、evenNumbersには偶数だけが入ります。

そのため、return num % 2 === 0の部分が抽出条件の本体になるのがポイントです。条件式を読むときは、どの要素が残るかをtrue側から考えると、否定条件を含む処理でも理解しやすくなります。

サンプルコード2:オブジェクト配列から条件に合う要素を抽出

その考え方は、nameageを持つオブジェクト配列にもそのまま使えます。オブジェクト配列のfilterの使い方では、プロパティにアクセスして条件式を作る点が中心になるのが一般的です。

const users = [{ name: '山田', age: 25 }, { name: '佐藤', age: 32 }, { name: '鈴木', age: 18 }, { name: '田中', age: 40 }]; const adultUsers = users.filter(function(user) { return user.age >= 20; }); console.log(adultUsers);

結果: 期待される出力は、ageが20以上のユーザーだけを含む配列です。

[{ name: '山田', age: 25 }, { name: '佐藤', age: 32 }, { name: '田中', age: 40 }]

結果: 期待される出力例では、18歳のユーザーだけが除外されます。

この例ではuser.age >= 20が判定条件です。user全体が配列要素なので、条件に合う場合はオブジェクトの一部ではなく、オブジェクトそのものが新しい配列に残ります。

これを画面表示に使う場合、抽出後の配列をそのまま一覧コンポーネントへ渡せますが、覚えておくと役立つでしょう。ただし、名前だけを取り出したい場合はfilter()の後にmap()を続けるなど、抽出と変換を分けて考える必要があります。

💡 Tips: filter()は元配列を変更しないため、抽出前のデータを別処理で再利用できます。破壊的な変更が必要な場面では、意図をコメントや関数名で区別すると読みやすくなるのが現実的です。

複数条件を指定してfilterを使う

複数条件を扱うときは、条件を並べるだけでなく評価順を読む人に伝える必要があります。そのため、&&||が混ざる条件では括弧を使い、判定のまとまりを明示するのが現実的です。

一方、条件式が長くなりすぎると、filterの使い方そのものより業務条件の読み取りが難しくなります。const isPremium = ...のように関数へ切り出す判断も、複数条件の保守では役立ちますし、ここを基本と考えるとよいでしょう。

これらの条件は、if文で書くこともできます。短い条件ならfilter()内に直接書き、意味のある業務判定ならisAdultUser()hasPremiumRank()のような関数名へ逃がすと、後から読んだときに意図が伝わります。

サンプルコード3:論理AND条件で要素を絞り込む

これにより、年齢条件とランク条件を同時に満たすユーザーだけを残せますし、ここがポイントです。&&は左辺と右辺の両方が真の場合に真になる演算子です。

const users = [{ name: '山田', age: 25, rank: 'ゴールド' }, { name: '佐藤', age: 32, rank: 'シルバー' }, { name: '鈴木', age: 18, rank: 'ゴールド' }, { name: '田中', age: 40, rank: 'プラチナ' }]; const premiumUsers = users.filter(function(user) { return user.age >= 20 && (user.rank === 'ゴールド' || user.rank === 'プラチナ'); }); console.log(premiumUsers);

結果: 期待される出力は、20歳以上かつ対象ランクのユーザー配列です。

[{ name: '山田', age: 25, rank: 'ゴールド' }, { name: '田中', age: 40, rank: 'プラチナ' }]

結果: 期待される出力例では、シルバーのユーザーと18歳のユーザーが除外されます。

この複数条件では、user.age >= 20を満たし、さらにランクがゴールドまたはプラチナである必要があります。||を括弧で囲むことで、年齢条件との結合が読み取りやすくなると整理できます。

その条件を候補リストで管理したい場合は、['ゴールド', 'プラチナ'].includes(user.rank)のように書けます。ランクが増える可能性がある画面では、値を配列へ切り出すほうが変更箇所を減らせます。

サンプルコード4:論理OR条件で要素を絞り込む

一方、どれか一つの条件に合えば残したい場合は||を使いると理解できます。会員ランクのように候補が限られる値では、includes()で候補配列にまとめる書き方も選べます。

const users = [{ name: '山田', age: 25, rank: 'ゴールド' }, { name: '佐藤', age: 32, rank: 'シルバー' }, { name: '鈴木', age: 18, rank: 'ゴールド' }, { name: '田中', age: 40, rank: 'プラチナ' }]; const highRankUsers = users.filter(function(user) { return user.rank === 'ゴールド' || user.rank === 'プラチナ'; }); console.log(highRankUsers);

結果: 期待される出力は、ランクがゴールドまたはプラチナのユーザー配列です。

[{ name: '山田', age: 25, rank: 'ゴールド' }, { name: '鈴木', age: 18, rank: 'ゴールド' }, { name: '田中', age: 40, rank: 'プラチナ' }]

結果: 期待される出力例では、シルバーだけが対象外になります。

この条件は年齢を見ていないため、18歳のユーザーも残ります。複数条件では、書いていない条件は評価されないという前提を明確に意識すると、抽出ミスを避けやすくなると覚えるとよいでしょう。

そのため、OR条件を追加するときは、対象にしたい属性が同じかどうかを確認します。ランクのような同一属性なら読みやすく、年齢や地域など別属性を混ぜるなら関数名で意味を補うほうが現実的です。

サンプルコード5:NOT条件で要素を除外する

逆に、特定の値だけを除外したいときは!==を使います。除外条件は読み間違いが起きやすいため、変数名にexcludewithoutを入れると目的が伝わりますが、これは押さえたい点です。

const users = [{ name: '山田', age: 25, rank: 'ゴールド' }, { name: '佐藤', age: 32, rank: 'シルバー' }, { name: '鈴木', age: 18, rank: 'ゴールド' }, { name: '田中', age: 40, rank: 'プラチナ' }]; const excludeSilverUsers = users.filter(function(user) { return user.rank !== 'シルバー'; }); console.log(excludeSilverUsers);

結果: 期待される出力は、ランクがシルバーではないユーザー配列です。

[{ name: '山田', age: 25, rank: 'ゴールド' }, { name: '鈴木', age: 18, rank: 'ゴールド' }, { name: '田中', age: 40, rank: 'プラチナ' }]

結果: 期待される出力例では、佐藤のオブジェクトだけが除外されます。

その条件はuser.rankシルバーではない場合に真になります。否定条件が増えると読みにくくなるため、複数条件が絡む場合は肯定形へ変換できないかを確認すると保守しやすくなると考えられます。

ただし、除外対象が複数ある場合はuser.rank !== 'シルバー' && user.rank !== 'ブロンズ'のように長くなります。この場合はexcludedRanks配列を作り、!excludedRanks.includes(user.rank)と書くと、複数条件でも意図を保ちやすくなります。

連想配列とオブジェクト配列でのfilterの活用

連想配列という表現はJavaScriptでは多くの場合オブジェクトを指し、{ key: value }の形で値を持ちますし、これが一つの目安です。ただし、filter()は配列メソッドなので、連想配列へ直接呼び出すのではなく、Object.entries()で配列へ変換してから使います。

オブジェクト配列では、各要素が{ name: '...' }のようなオブジェクトです。そのため、filterの使い方は配列の繰り返しとプロパティ参照の組み合わせとして考えると整理できます。

具体的には、Object.keys()Object.values()Object.entries()を目的に応じて選びますが、覚えておくと役立つでしょう。仕様はMDNのObject.entries()MDNのObject.fromEntries()で確認できます。

これらのメソッドを使うと、連想配列を一時的に配列として扱えます。キーも条件に使うならentries()、値だけで十分ならvalues()、キー一覧だけが必要ならkeys()を選ぶと、処理の目的が明確になると言えるでしょう。

サンプルコード6:連想配列から条件に合うプロパティを抽出

これらを組み合わせると、在庫データのような連想配列から条件に合う項目だけを残せます。Object.entries()[key, value]形式にしてからquantityを判定します。

const inventory = { apple: 15, banana: 8, orange: 12, grape: 20, melon: 3 }; const inStock = Object.entries(inventory).filter(function([item, quantity]) { return quantity >= 10; }); console.log(Object.fromEntries(inStock));

結果: 期待される出力は、在庫数が10以上の商品だけを持つオブジェクトです。

{ apple: 15, orange: 12, grape: 20 }

結果: 期待される出力例では、bananamelonが除外されます。

この処理では、分割代入の[item, quantity]によってキーと値を取り出しています。itemを条件で使わない場合でも、キー名が必要になる拡張を見越して残す書き方は自然です。

その後のObject.fromEntries()は、抽出済みのキーと値の組を再びオブジェクトへ戻するのが基本です。連想配列の形を保ったまま在庫条件を反映できるため、設定値や集計値を扱う処理にも応用できます。

サンプルコード7:オブジェクト配列から条件に合うオブジェクトを抽出

そのまま配列になっているオブジェクト配列なら、変換せずにfilter()を呼び出せます。出版年と評価の複数条件を使うことで、条件に合う書籍だけを取り出するのが目安です。

const books = [{ title: 'JavaScriptの基本', author: '山田太郎', year: 2015, rating: 4.2 }, { title: 'HTMLとCSSの入門', author: '鈴木花子', year: 2018, rating: 4.5 }, { title: 'Pythonで学ぶ機械学習', author: '田中一郎', year: 2020, rating: 4.8 }, { title: 'Rubyのウェブアプリ開発', author: '佐藤次郎', year: 2008, rating: 3.8 }]; const recentHighRatedBooks = books.filter(function(book) { return book.year >= 2010 && book.rating >= 4; }); console.log(recentHighRatedBooks);

結果: 期待される出力は、2010年以降かつ評価4以上の書籍配列です。

[{ title: 'JavaScriptの基本', author: '山田太郎', year: 2015, rating: 4.2 }, { title: 'HTMLとCSSの入門', author: '鈴木花子', year: 2018, rating: 4.5 }, { title: 'Pythonで学ぶ機械学習', author: '田中一郎', year: 2020, rating: 4.8 }]

結果: 期待される出力例では、2008年で評価3.8の書籍が対象外になります。

この条件ではbook.yearbook.ratingの両方を評価します。商品一覧やユーザー一覧でも同じ構造を使えるため、オブジェクト配列のfilterは管理画面や検索画面と相性がよい処理です。

ただし、表示に不要なプロパティまで残る点は意識するのがポイントです。必要な項目だけを返したい場合は、抽出後にmap()titleratingだけへ変換すると、表示側のデータ形が扱いやすくなります。

サンプルコード8:ネストしたオブジェクト配列の処理

ネストしたオブジェクト配列では、user.address.cityのように階層をたどって条件を作ります。このとき、配列を含むプロパティにはincludes()を組み合わせると、含有チェックが短く書けるのが一般的です。

const users = [{ name: '山田太郎', age: 28, address: { city: '東京', ward: '渋谷区' }, hobbies: ['音楽', '旅行'] }, { name: '鈴木花子', age: 32, address: { city: '大阪', ward: '北区' }, hobbies: ['読書', '料理', 'スポーツ'] }, { name: '田中一郎', age: 25, address: { city: '東京', ward: '新宿区' }, hobbies: ['映画', 'スポーツ', 'ゲーム'] }]; const tokyoSportsFans = users.filter(function(user) { return user.address.city === '東京' && user.hobbies.includes('スポーツ'); }); console.log(tokyoSportsFans);

結果: 期待される出力は、東京在住で趣味にスポーツを含むユーザー配列です。

[{ name: '田中一郎', age: 25, address: { city: '東京', ward: '新宿区' }, hobbies: ['映画', 'スポーツ', 'ゲーム'] }]

結果: 期待される出力例では、田中一郎のオブジェクトだけが残ります。

ただし、addressが存在しないデータが混ざる場合はuser.address.cityで例外が起きます。その場合はuser.address?.cityのようなオプショナルチェーンを使うと、欠損データを含む一覧でも判定しやすくなるのが現実的です。

このときhobbiesも配列とは限らないなら、Array.isArray(user.hobbies)を先に確認します。外部APIのレスポンスでは型が揺れることがあるため、filter条件の前提を小さく保つと障害を切り分けやすくなります。

⚠️ 注意: 外部APIのレスポンスを扱う場合、プロパティの欠損やnullが混ざることがあると整理できます。?.や初期値を使い、条件式が例外で止まらない形に整えると安全です。

アロー関数を使ったfilterの応用

アロー関数は、短い判定関数を読みやすくする書き方です。JavaScriptのfilter()ではコールバック関数を書く機会が多いため、アロー関数を使うと条件式に視線を集めやすくなります。

一方、functionとアロー関数ではthisの扱いが異なります。詳しい仕様はMDNのアロー関数式で確認でき、thisArgを使うコードでは違いを意識する必要があると理解できます。

基本的に、filter()の条件だけを書くならアロー関数で十分です。ただし、オブジェクトのメソッドとしてthisを参照したい処理では、通常のfunctionを選ぶほうが意図に合う場合があります。

アロー関数の基本文法

基本的な構文では、左側に引数、右側に処理を書きます。処理が複数行なら{}returnを使い、単一式なら暗黙の戻り値として短くできると覚えるとよいでしょう。

(引数1, 引数2, ...) => { return 戻り値; }

結果: 期待される形として、引数を受け取り、returnした値を返す関数になります。

通常の関数宣言では、functionキーワードを使って名前付き関数を定義します。これは再利用する関数や、意図的に巻き上げを使う関数で読みやすい選択になる場合があると考えられます。

function add(a, b) { return a + b; }

結果: 期待される戻り値は、abを足した数値です。

同様に、アロー関数でも同じ計算を書けます。constへ関数を代入する形になるため、関数を値として扱う考え方と相性があります。

const add = (a, b) => { return a + b; };

結果: 期待される戻り値は、通常の関数宣言と同じ加算結果です。

処理が1行で終わる場合は、ブロックとreturnを省略できると言えるでしょう。filterのアロー関数でも、この短い形がよく使われます。

const add = (a, b) => a + b;

結果: 期待される戻り値は、a + bの評価結果です。

その省略形は、戻り値が単一式である場合だけ成立します。オブジェクトリテラルを返すときは({ name: value })のように括弧が必要になるため、後続のmap()と組み合わせるときは特に注意するのが基本です。

サンプルコード9:アロー関数を使ってシンプルに記述する

これを偶数抽出に使うと、条件式だけが前面に出ます。num => num % 2 === 0は、numを受け取り、偶数なら真を返す関数です。

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; const evenNumbers = numbers.filter(num => num % 2 === 0); console.log(evenNumbers);

結果: 期待される出力は、偶数だけを含む配列です。

[2, 4, 6, 8, 10]

結果: 期待される出力例は、通常のfunctionで書いた場合と同じです。

この書き方は短い条件に向いています。ただし、条件に副作用を入れると読みづらくなるため、console.log()や状態変更を混ぜず、判定だけに絞るほうが扱いやすくなります。

そのため、チームで読むコードでは、短さだけを目的にしないほうがよいでしょう。条件が長くなったらアロー関数のまま関数へ切り出し、numbers.filter(isEven)のように名前で意図を伝える方法もあるのが目安です。

サンプルコード10:三項演算子とアロー関数を組み合わせる

三項演算子は条件 ? 真の場合 : 偽の場合の形で値を返します。ただし、filter()では返り値が真偽値として評価されるため、文字列を返す例は教育用の挙動確認として読む必要があります。

const numbers = [5, 12, 8, 20, 3, 15]; const judgements = numbers.filter(num => num >= 10 ? '大きい' : '小さい'); console.log(judgements);

結果: 期待される出力は、実質的に全要素が残る配列です。どちらの文字列も真と評価されるためです。

[5, 12, 8, 20, 3, 15]

結果: 期待される出力例では、大きい小さいではなく元の数値が残ります。

そのため、分類結果を得たい場合はfilter()ではなくmap()を使います。抽出はfilter()、変換はmap()と分けると、アロー関数の使い方も自然に整理できるのがポイントです。

この例から分かるのは、filter()が返り値そのものを新しい配列へ入れるわけではない点です。返り値は残すか除外するかの判定に使われ、残る値は元配列の要素になります。

ℹ️ 補足: filter()のコールバックは、返した値そのものを配列へ入れるわけではありません。返り値を真偽値として評価し、元の要素を残すかどうかだけを決めます。

よくあるエラーと対処法

初心者がつまずきやすいのは、配列ではない値にfilter()を呼び出すケースです。JavaScriptではundefinednullにメソッドを呼び出せないため、変数の初期化と型確認が対処の中心になるのが一般的です。

そのほか、APIレスポンスが配列ではなくオブジェクトだった、HTML要素のNodeListに配列メソッドを直接使った、といった混同も起こりやすいです。必要に応じてArray.isArray()Array.from()を使うと、原因を切り分けやすくなります。

これらのエラーは、filterの使い方を間違えたというより、対象データの型が想定と違うことで起きます。データ取得直後にconsole.log(typeof value)Array.isArray(value)で形を確認すると、原因に近づきやすくなるのが現実的です。

TypeError: Cannot read properties of undefined (reading ‘filter’)

このエラーは、undefinedに対してfilterプロパティを読もうとしたときに起きます。変数宣言だけで値を代入していない場合、次のようなコードで発生します。

let numbers; numbers.filter(num => num > 10);

結果: 期待されるエラーメッセージは、undefinedからfilterを読めないという内容です。

TypeError: Cannot read properties of undefined (reading 'filter')

結果: 期待される表示は、numbersが配列ではないことを示すエラー文です。

この場合は、numbersへ配列を代入してからfilter()を呼び出します。外部データを受け取る処理では、初期値を[]にしておく設計も有効です。

let numbers = [5, 12, 8, 20, 3, 15]; const filteredNumbers = numbers.filter(num => num > 10); console.log(filteredNumbers);

結果: 期待される出力は、10より大きい数値だけを含む配列です。

[12, 20, 15]

結果: 期待される出力例では、122015だけが残ります。

ただし、受け取る値が常に配列とは限らない場合は、Array.isArray(numbers)で確認してから処理します。forEachでreturnを使う処理でも同じく、配列かどうかの確認が読みやすい分岐につながりますし、ここを基本と考えるとよいでしょう。

その分岐は、空配列を返す形にすると後続処理が安定します。たとえばconst safeNumbers = Array.isArray(numbers) ? numbers : []のように整えてからfilterを呼び出すと、画面側で例外を受けにくくなります。

filter関数の応用的な使い方

応用的な使い方では、文字列検索、正規表現、map()との連携、重複排除を組み合わせますし、ここがポイントです。filterは抽出に特化し、変換や集約は別メソッドへ任せると、処理の目的が読み取りやすくなります。

具体的には、検索ボックスの入力値を使って商品名を絞る、在庫ありの商品だけを表示用データへ変換する、タグ一覧から重複を外すといった処理があります。イベント入力と組み合わせる場合は、JavaScriptイベントの使い方イベントハンドラの基本も合わせて確認すると、画面側の流れまで整理できると整理できます。

一方、すべての抽出をfilter()だけで解決しようとすると、条件式が膨らみます。検索条件が増える画面では、入力値を正規化し、条件ごとの判定関数を分けてから、最後にfilter()へ渡す構成が読みやすくなります。

サンプルコード11:配列の部分一致検索

部分一致検索では、toLowerCase()で比較対象をそろえてからincludes()で含有を調べますが、これは押さえたい点です。これにより、ユーザーが小文字で入力しても大文字を含む商品名に一致しやすくなります。

const products = ['Apple iPhone 12', 'Samsung Galaxy S21', 'Google Pixel 5', 'OnePlus 9 Pro', 'Xiaomi Mi 11']; const keyword = 'pro'; const searchResults = products.filter(product => product.toLowerCase().includes(keyword.toLowerCase())); console.log(searchResults);

結果: 期待される出力は、検索語を含む商品名だけの配列です。

['OnePlus 9 Pro']

結果: 期待される出力例では、proに一致するOnePlus 9 Proだけが残ります。

この処理では、productkeywordの両方を小文字へ変換しています。表記ゆれをある程度吸収できますが、全角半角やひらがなカタカナの揺れまでは扱わないため、検索要件に応じて正規化を検討すると理解できます。

その検索を入力イベントと連動させる場合、入力のたびに配列を絞り込む構成になります。データ件数が多いときは、入力値が空なら元配列を返す、一定文字数以上で検索するなど、画面の負荷も考慮します。

サンプルコード12:大文字小文字を区別しない検索

同様に、正規表現のiフラグでも大文字小文字を区別しない検索ができると覚えるとよいでしょう。RegExp.prototype.test()は、対象文字列がパターンに合うかを真偽値で返します。

const products = ['Apple iPhone 12', 'Samsung Galaxy S21', 'Google Pixel 5', 'OnePlus 9 Pro', 'Xiaomi Mi 11']; const keyword = 'pro'; const searchResults = products.filter(product => new RegExp(keyword, 'i').test(product)); console.log(searchResults);

結果: 期待される出力は、正規表現に一致した商品名だけの配列です。

['OnePlus 9 Pro']

結果: 期待される出力例では、Proの大文字を区別せずに一致します。

ただし、ユーザー入力をそのままnew RegExp()へ渡すと、.*などが正規表現として解釈されます。文字列検索だけが目的ならincludes()、パターン検索が必要ならエスケープ処理を検討する使い分けが必要です。

これに対して、正規表現は前方一致、末尾一致、複数語の一致などを表現できると考えられます。単純な部分一致を超える要件では役立ちますが、条件が複雑なほどテストケースを明確にしておく必要があります。

サンプルコード13:他の配列メソッドと組み合わせる

抽出後に表示用の形へ変える場合は、filter()の後ろにmap()をつなげます。先に在庫条件で絞り込み、その後でnamepriceだけを取り出す流れです。

const products = [{ name: '商品A', price: 1000, stock: 15 }, { name: '商品B', price: 2000, stock: 8 }, { name: '商品C', price: 1500, stock: 12 }, { name: '商品D', price: 500, stock: 20 }]; const inStockProducts = products.filter(product => product.stock >= 10).map(product => ({ name: product.name, price: product.price })); console.log(inStockProducts);

結果: 期待される出力は、在庫数10以上の商品を名前と価格だけに変換した配列です。

[{ name: '商品A', price: 1000 }, { name: '商品C', price: 1500 }, { name: '商品D', price: 500 }]

結果: 期待される出力例では、在庫8の商品Bが除外され、残った商品は表示向けの形になります。

この連鎖では、各メソッドが新しい配列を返します。大量データで処理回数が気になる場合は別の設計も候補になりますが、一般的な画面表示では読みやすさを優先するほうが保守しやすいでしょう。

その順序は、先にmap()してからfilter()する場合と意味が変わりますし、これが一つの目安です。不要な要素を先に落としてから表示用に変換するほうが、条件と出力形式を分けて読みやすくなります。

サンプルコード14:ユニークな値のみ抽出する

重複を除外するだけなら、filter()以外の選択肢としてSetがあります。単純な文字列や数値の重複排除では、new Set()とスプレッド構文...の組み合わせが短く書けると言えるでしょう。

const tags = ['JavaScript', 'HTML', 'CSS', 'React', 'JavaScript', 'Vue', 'CSS']; const uniqueTags = [...new Set(tags)]; console.log(uniqueTags);

結果: 期待される出力は、重複を除いたタグ配列です。

['JavaScript', 'HTML', 'CSS', 'React', 'Vue']

結果: 期待される出力例では、重複していたJavaScriptCSSが一度だけ残ります。

この方法は、同じ値かどうかをSetの仕組みで判断します。一方、オブジェクト配列でidごとに重複を消す場合は、Mapfilter()findIndex()を組み合わせるなど、キーを基準にした処理が必要になるのが基本です。

ちなみに、ファイル名や拡張子を条件に配列を絞る処理でも同じ考え方を使えます。拡張子判定の具体例はJavaScriptで拡張子を活用する方法と合わせて読むと、文字列処理とのつながりが見えます。

その重複排除をfilter()で書く場合は、array.indexOf(value) === indexのように現在位置と初回位置を比べますが、覚えておくと役立つでしょう。ただし、単純値の配列ではSetのほうが意図を読み取りやすく、オブジェクト配列ではキーを決める設計が先になります。

まとめ

JavaScriptのfilter関数は、配列から条件に合う要素だけを取り出すための中心的なメソッドです。基本構文ではcallbackが真と評価した要素だけが新しい配列へ入り、元の配列は変更されません。

複数条件を扱う場合は、&&||!==を組み合わせ、括弧で評価順を明確にします。連想配列ではObject.entries()で配列へ変換し、オブジェクト配列ではプロパティ参照を使って条件を作ると整理できるのが目安です。

アロー関数を使うと短い条件式を簡潔に書けますが、thisや戻り値の意味には注意が必要です。抽出はfilter()、変換はmap()、重複排除はSetというように役割を分けると、使い方の判断がしやすくなります。

エラー対策では、対象が配列かどうかをArray.isArray()で確認し、欠損プロパティには?.を検討します。こうした基本を押さえると、検索、一覧表示、入力値の除外、オブジェクト配列の抽出まで同じ考え方で対応できるのがポイントです。

実装パターンとしてよく見るのは、取得した一覧データを状態として保持し、検索語やチェックボックスの値に応じてfilter()した配列を表示する構成です。この構成では元データを残せるため、検索条件を解除したときに再取得せず元の一覧へ戻しやすくなります。

ただし、抽出条件が複雑になった場合は、コールバック内へ処理を詰め込まないほうが読みやすくなります。isTargetUser(user)matchesKeyword(product, keyword)のような関数名を付けると、複数条件の意図が本文のように読めるのが一般的です。

この整理を意識すると、連想配列、オブジェクト配列、文字列配列のどれを扱っても判断軸が変わりません。配列に変換する必要があるか、どのプロパティを見るか、返り値が真偽値として正しいかを順に確認すれば、filterの使い方は安定します。

一般的に、JavaScriptの配列処理は小さなメソッドを組み合わせるほど読みやすくなります。filter()で対象を減らし、map()で形を変え、必要に応じてreduce()で集計する流れを意識すると、データ処理の見通しが整いるのが現実的です。

関連記事

著者: Japanシーモア編集部

Japanシーモアは、Web/IoT/APP/SYS 分野のプログラミング情報を体系的に提供するメディアです。本記事は編集部による執筆とAI支援を組み合わせて制作し、公開前に編集部が校正しています。誤りや改善案がございましたらお問い合わせよりご連絡ください。

※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。