脱 for, forEach !
皆さんこんにちは、江嵜です。
みなさん、JavaScript の配列、よく使いますよね?
配列を操作するときってどうしてますか?
例えば簡単な足し算の場合、
こんなんとか
var hoge = [1, 2, 3]; var sum = 0; for (var i = 0; i < hoge.length; i++) { sum += hoge[i]; } console.log(sum); // => 6
こんなんとか?
var hoge = [1, 2, 3]; var sum = 0; hoge.forEach(function(v) { sum += v; }); console.log(sum); // => 6
もちろん、これも正解ですよね。
過程がどうであれ、目的が達成できればいいですし。
でも、今はもっといい書き方もあるんです!
JavaScript の配列で使える便利なメソッドたち
JavaScript の配列に対して、 for, forEach() の代わりに使える
便利なメソッドをいくつか紹介してみましょう!
reduce
reduce は先ほどの足し算のように、配列からある一つの値を導き出したいときに使えるメソッドです。
先程の足し算を書き換えてみると…
var hoge = [1, 2, 3]; var sum = hoge.reduce((prev, current) => prev += current, 0); console.log(sum); // => 6
実質一行で書けましたね!
なぜこう書けるのかが分からないと意味不明で気持ち悪い感じですが、
慣れると一瞬で書けるようになります。
ただ、慣れていないとさすがに考えることが多すぎるのでちょっと見慣れた形に変形させて…
var hoge = [1, 2, 3]; function calc(prev, current) { return prev += current; } var sum = hoge.reduce(calc, 0); console.log(sum); // => 6
これで順を追って説明しましょう!
- reduce は
配列.reduce(コールバック関数, 初期値)
の形で使います。
この場合は、コールバック関数が calc, 初期値が 0 です。 - reduce は配列の先頭から一つずつ値を取り出して計算して、取り出して計算して、を繰り返すメソッドです
(ちなみにこの後ご紹介するメソッドもすべて、配列の先頭から一つずつ取り出して、処理して、を繰り返す挙動になります) - コールバック関数の引数には (前回の結果, 今回取り出した値) の形で値が格納されます
実際の処理の流れは
- まず最初に、配列には 1 が格納されているので、 「今回取り出した値」が 1、「前回の結果」は無いので(初回なので)別途設定した初期値 0 が 前回の結果に入ります
- コールバック関数を実行すると
prev += current
、すなわち 「今回取り出した値」+= 「前回の結果」 なので、 1 + 0 で 1 が返されます。 - 配列一つ目の値について reduce した結果
1
という結果を得ました
(ここまででワンセットです) - 配列一つ目の値について計算終了したので、二つ目の値の値を取り出します。 2 ですね
- 今回取り出し値は 2, 前回の結果が 1 なので 2 + 1 で 3 が返されます
- もう一度、次の値を配列から取り出すと今度は 3 です
- 前回の結果が 3, 今回の値が 3 なので 3 + 3 で 6 が返されます。
- 次の値を配列から取り出そうとしますが、もう値がないので終了です
最終結果の 6 を返します
これが sum 変数に格納されます。
ちょっと長いですが、こんな感じの処理になります。
一言で言えば、単純に一つずつ取り出して順番に計算していくだけ、ですね。
今回は足し算に使いましたが、名簿リスト等に使って
名前の一覧を一つの文字列にまとめるみたいな使い方もできますね。
map
map は配列のそれぞれの値に対して何らかの操作を行い、新しい配列を作るメソッドです。
配列の中の値をそれぞれ 3 倍した配列を作ってみましょう。
var hoge = [1, 2, 3]; var result = hoge.map(x => x * 3); console.log(result); // => [3, 6, 9]
驚きの短さ!
これも少し変形しますね。
var hoge = [1, 2, 3]; function calc(value) { return value * 3; } var result = hoge.map(calc); console.log(result); // => [3, 6, 9]
これは reduce よりもちょっと簡単です。
- 配列から一つ目の値を取り出してコールバック関数の第一引数にセットします
この場合 value に 1 がはいりますね - コールバック関数の中を実行します。
value * 3
なので1 * 3
で 3 が返ってきます。 - 帰ってきた値 3 を別の配列にセットします(別の配列はこのコードでは特に作っていませんが、 map がこっそり新しく作ります)
- 次の値 2 を取り出します…
と順々に実施していって、最終的に出来上がった配列を返す、というところですね。
DB への値の格納前などに配列の中身を変換したいということはよくあるので、覚えておくと結構便利な存在ですね。
filter
配列の便利なメソッドはたくさんあるのですが、とりあえずここではもう一つだけご紹介いたします。
filter は配列の中から条件に合うものだけを抽出して新しい配列にするメソッドです。
例えば偶数の数だけを抽出するには…
var hoge = [3, 6, 7, 10, 15]; var sum = hoge.filter(x => x % 2 === 0); console.log(sum); // => [6, 10]
これもちょっと変換すると、
var hoge = [3, 6, 7, 10, 15]; function check(value) { var rem = value % 2; var isEven = rem === 0; return isEven; } var result = hoge.filter(check); console.log(result); // => [6, 10]
こんな感じですね。
ここまで二つ見たので大分慣れてきたかなと思います。
こちらはコールバック関数の中で true, false を返します。
他のメソッド同様値を一つ取り出して、計算をします。
- rem には 2 で割った余りが入ります
3 (奇数) なら 1, 6 (偶数) なら 0 ですね - isEven には true または false が入ります
0 なら true なので、偶数なら true ということですね - 最後に isEven を返します
すると、 filter は true が返された値だけを配列に書き出し、最後に配列を返してくれるのですね。
なんで for, forEach を書きたくないのか?
皆さんの中には、「なんでそこまでして for, forEach を削るの?別にそのままで良くない?」と思っていらっしゃる方もおられるでしょう。
実は私も前はそう思っていました。
ですが、一度習得して使ってみると分かるのですが、
- 書くときにラク (別に変数を用意したりとかしなくて良いし、短く書けることをが多い)
- 読むときにラク(for だけではただ繰り返す、という事しか分からないが、 map なら配列を変換をしたいという意図がすぐにわかる)
と、ラクラクなんですね!
今回は JavaScript を例にご紹介しましたが、こういったラムダ式等は Java や PHP など、ほかにも使える言語は多くあります。
これまで使ったことがない!という方はこれを機に使ってみてくださいね。