まえがき
皆さん.map()
と.reduce()
に頼り過ぎてませんか?少なくとも私は頼りまくってます。
値にそれぞれ処理をしたいなら.map()
、全体をまとめたりしたいときは.reduce()
を使えばおそらくすべての場合に方が付くのではないかと思いますが、往々にして冗長になりがちです。
これはそんな人に送りたいJavaScriptのプロトタイプメソッドって結構いっぱいありますよというお話です。
.every()
const arr = [10, 20, 30, 40, 50];
// .reduce()を使った方法
arr.reduce((pre, cur) => pre && cur > 0, true)
// .every()を使った方法
arr.every((item) => item > 0)
全ての要素が条件を満たしているならtrue
、でなければfalse
を返すような関数です。.reduce()
よりもスッキリしていていいですね!
気になったのでパフォーマンスも測ってみました。ちなみに環境はNode.jsです。
長さ10000の配列に対して1000000回処理する時間を計測した結果です。
メソッド | 時間 |
---|---|
.reduce() |
6784ms |
.every() |
5ms |
1000倍ほどパフォーマンスに差が出てますね。
検証用に使ったコードはこちら
const arr = new Array(10000).fill(0).map((_, i) => i);
const sleep = async (ms) =>
new Promise((resolve) => setTimeout(() => resolve(), ms));
const measure = async (f, count) => {
let sum = 0;
for (let j = 0; j < 100; j++) {
const start = performance.now();
for (let i = 0; i < count; i++) {
f();
}
sum += time = performance.now() - start;
await sleep(100);
}
return sum / 100;
};
// ここに検証用するものを入れる
const f = () => arr.reduce((pre, cur) => pre && cur > 0, true);
measure(f, 1000000).then((time) => console.log(time));
※sleep(100)
を入れてるのは実行した時々で値が結構ブレるのでそれを吸収するためです。
.some()
const arr = [10, 20, 30, 40, 50];
// .reduce()を使った方法
arr.reduce((pre, cur) => pre || cur > 100, false)
// .find()を使った方法
arr.find((item) => item > 100) !== undefined
// .some()を使った方法
arr.some((item) => item > 100)
少なくとも1つの要素が条件を満たしているならtrue
、でなければfalse
を返すような関数です。同じことは.find()
や.reduce()
を使ってもできますが、少し冗長になってしまいますね。
長さ10000の配列に対して1000000回処理する時間を計測した結果です。
メソッド | 時間 |
---|---|
.reduce() |
6381ms |
.find() |
89ms |
.some() |
77ms |
.find()
はそこそこ早いですが、.some()
の方が見やすいですし良いでしょう。
.flatMap()
const arr = [1, 2, 3, 4, 5];
// .map()と.reduce()を使った方法
arr.map((item) => [item, item * 10]).reduce((pre, cur) => [...pre, ...cur], [])
// .map()と.flat()を使った方法
arr.map((item) => [item, item * 10]).flat()
// .reduce()と.concat()を使った方法
arr.reduce((acc, item) => acc.concat([item, item * 10]), [])
// .flatMap()を使った方法
arr.flatMap((item) => [item, item * 10])
.map()
した後に配列を深さ1で平坦化するような関数です。色々なやり方がありますが、.flatMap()
が一番シンプルでわかりやすいですね。
長さ1000の配列に対して1000回処理する時間を計測した結果です。(ここだけ処理が少ないのは時間がかかり過ぎたからです)
メソッド | 時間 |
---|---|
.map() +.reduce()
|
2308ms |
.map() +.flat()
|
590ms |
.reduce() +.concat()
|
1230ms |
.flatMap() |
651ms |
.reduce()
を使ってるやつらは遅いですがそれ以外もそれなりに遅いですね。配列の平坦化は負荷が大きいんでしょうか...?
.map()
+.flat()
と.flatMap()
はあまり差がありませんが、これらは内部処理がほとんど同じらしいので、それが理由なのかなと思います。
まとめ
パフォーマンス的にも可読性的にも.every()
・.some()
・.flatMap()
を使おう!!!
もし他のネタがあったらコメントなりで教えてください。