filter() は、配列の1つ1つを関数に通して、戻り値が真になった要素だけを集めた新しい配列を返します。
元の配列は変わりません。要素数は減ることがあります。
上のコードは書き換えて実行できます。n % 2 === 0 を n > 3 にしてみてください。
何が返るのか
| 中身 | |
|---|---|
| 戻り値 | 新しい配列。長さは元以下 |
| 元の配列 | 変わらない |
| 呼ばれる回数 | 要素の数だけ |
| 1つも通らなかったとき | 空配列(null ではない) |
filter() は非破壊的メソッドです。
1つも通らなくても null にならない
見つからなかったときに null や undefined が返ると思って書くと、そこで詰まります。
必ず配列が返ります。
判定は if (even) ではなく even.length === 0 で書きます。
空配列は truthy です。if (even) は必ず通ってしまいます。
コールバック関数が受け取るもの
map() と同じで、3つの引数が渡されます。
const nums = [0, 1, 2, 3];
const picked = nums.filter(n => n);
console.log(picked);真偽値でなくてもよい(truthy / falsy で判定される)
戻り値は true / false でなくて構いません。truthyなら残り、falsyなら落ちます。
この性質を使うと、空の値をまとめて落とす書き方ができます。
const nums = [1, 2, 3];
const result = nums.filter((n) => {
nums.push(n * 10);
return true;
});
console.log(result);
console.log(nums.length);filter(Boolean) は「falsy を全部落とす」という意味になります。
falsy は false / 0 / -0 / 0n / '' / null / undefined / NaN の8つだけです。それ以外は全部 truthy です。
よくある間違い
値を返してしまう
filter() に渡すのは残すかどうかの判定です。値を返すと、その値が truthy かどうかで判定されます。
0 が意図せず落ちました。n を残したいのではなく n が falsy かどうかを見ています。
値を変換したいときは filter() ではなく map() を使います。
1件だけ欲しいのに filter を使う
先頭の1件だけが欲しいなら find() です。
filter() は最後まで全部見ます。
| 戻り値 | 見つからないとき | どこまで見るか | |
|---|---|---|---|
filter() |
配列 | 空配列 | 最後まで |
find() |
要素そのもの | undefined |
見つかった時点で止まる |
find() が undefined を返したことに気づかず、そのままプロパティを読むと
Cannot read properties of undefined
になります。空振りしたときにどうするかを、その場で決めてください。
穴のあいた配列では、穴が消える
要素が入っていない位置(疎な配列の穴)ではコールバック関数が呼ばれません。
そして結果の配列に穴は残りません。ここが map() と違います。
map() は長さを保つので穴がそのまま残り、filter() は通ったものを詰め直すので穴が消えます。
表示のしかたは処理系によって違います。上は Node 22.22.3 の出力です。
途中で元の配列を変えない
filter() は走り始めた時点の長さを覚えています。実行中に要素を足しても見に行きません。
元の配列は6件に増えたのに、結果は3件のままです。
ループの中で元の配列を変えない。これは map() でも forEach() でも同じです。