LINDORのAdvent Calendar(本物)の12日目を開けたところ。
配列とかおれおれAdvent Calendar2018 – 12日目

配列の中から条件に合致するものだけに絞るやつです。

const users = [
  { id: 101, name: 'Alice', active: true },
  { id: 102, name: 'Bob', active: false },
  { id: 103, name: 'Charlie', active: true },
];

const activeUsers = users.filter((v) => v.active);
console.log(activeUsers);

仕様

配列のこれ系のメソッドと同じです。

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

引数

filter() は引数に、関数オブジェクト callback(element[, index[, array]]) をひとつ受け取ります。

与える関数には、3つの引数が与えられます。 また前述のように boolean 値を返してください。

  • value … 配列の要素
  • index … インデックス
  • array … 操作中の配列本体

戻り値

関数 callbacktrue (ないし truthy なもの)を返した際の要素だけを格納した、新しい配列を返します。

該当がなかった場合でも要素数0の配列を返します。

undefined を除く

何かやった結果として undefined 混じりの情報を得るみたいな場面。

const result = [
  'foo',
  undefined,
  '',
  'hoge',
  undefined,
  'bar',
];

const validResult = result.filter((v) => v !== undefined);
console.log(validResult); // => [ 'foo', '', 'hoge', 'bar' ]

空文字列等の falsy なものもまとめて除いで良い場合は (v) => v で。短い。

アクティブユーザーだけ

フラグを含むオブジェクトの配列から対象のものだけを抜き出す場面。

const users = [
  { id: 101, name: 'Alice', active: true },
  { id: 102, name: 'Bob', active: false },
  { id: 103, name: 'Charlie', active: true },
];

const activeUsers = users.filter((v) => v.active);
console.log(activeUsers);
// => [ { id: 101, name: 'Alice', active: true },
//      { id: 103, name: 'Charlie', active: true } ]

チェックボックスで選択されたものだけ

document.querySelectorAll() は複数の要素を配列風オブジェクト NodeList で返します。 [...els] でそれを本物の配列へ変換し、 filter() で選択されたものだけにしてから map() で要素からその値を取り出しします。

(コードは抜粋)

<form id="the-form">
  <input type="checkbox" name="favorite" value="apple"> Apple
  <input type="checkbox" name="favorite" value="banana"> Banana
  <input type="checkbox" name="favorite" value="orange"> Orange
</form>
const elFavorites = document.querySelectorAll('#the-form [name="favorite"]');
const favorites = [...elFavorites]
  .filter((el) => el.checked)
  .map((el) => el.value);
console.log(favorites);

他の配列で指定されたID

前項のチェックボックスがIDだったとして、また別の配列からをその選択されたやつだけに絞る場合。

const users = [
  { id: '101', name: 'Alice' },
  { id: '102', name: 'Bob' },
  { id: '103', name: 'Charlie' },
];
const selectedIds = ['101', '102'];

const activeUsers = users.filter((v) => selectedIds.includes(v.id));
console.log(activeUsers);
// => [ { id: '101', name: 'Alice' }, { id: '102', name: 'Bob' } ]

その他のメソッド

「絞り込む」以外の用途に合うメソッドがあるので、それぞれ使い分けましょう。

絞り込んだ結果を使って何かするなら map()

find() 後に map() を組み合わせると便利です。

前述したチェックボックスの例を参考に。

ひとつだけ選択する

対象のものが1つとわかっている場合は find() が便利です。

const users = [
  { id: '101', name: 'Alice' },
  { id: '102', name: 'Bob' },
  { id: '103', name: 'Charlie' },
];

const id = '102';
const targetUser = users.find((v) => v.id === id);
console.log(targetUser);
// => { id: '102', name: 'Bob' }

あるかどうかだけわかれば良いなら some()

const existing = users.some((v) => v.id === targetId);
if (existing) {
  console.log('あったよ。');
}
else {
  console.log('なかったよ。');
}

全てが合致するか確認するなら every()

おまけ: あのアイコン

配列とは関係ないんだけど、UI上でフィルターの意味でしばしば使われるじょうご(ろうと、漏斗)、英語だと funnel だそうです。

Font Awesomeの “filter” 。

ガンダムのファンネルは、最初はその形状から名づけられたとか。その後ファンネルだけで例の小型遠隔兵器を指すようになり、フィン・ファンネルとかシールド・ファンネルとか出てくると。発展するにつれ語源から遠ざかるのは世の常ですね。

今日こんにちは! 然様さようなら!

おしまい

関連

参考