[1,2,3].reduce(function(a,b){return a + b});// 6
sum(配列の合計を求め)るとき、reduceを使うと便利ですが、いくつか注意すべき点があります。
.length
が 0
で失敗
空の配列に.reduce
を使用すると、例外を起こします。
[].reduce(function(a,b){return a + b});
// Uncaught TypeError: Reduce of empty array with no initial value
これは、第二引数に 0
を与えれば解決します。
[].reduce(function(a,b){return a + b},0);// 0
.length
が 1 で成功、だが…
数値であれば意図通りです。
[1].reduce(function(a,b){return a + b},0);// 1
コレクションの場合、失敗します。
[{value:1}].reduce(function(a,b){return (a.value!=null? a.value: a) + b.value});
// {value: 1}
MDNにはこうあります。
var result = array.reduce(callback[, initialValue]);
callback
4 つの引数を取って、配列内の各値に対し実行するコールバック関数
previousValue
現在処理されている配列要素の 1 つ前の要素。もしくは、initialValue
。initialValue
> については、後で述べます。
currentValue
現在処理されている配列要素
index
現在処理されている配列要素のインデックス
array
reduce
に呼ばれた配列
initialValue
callback
の最初の呼び出しのときに、最初の実引数として用いるためのオブジェクト。
関数が呼び出される初回は、previousValue
とcurrentValue
は 2 つの値のうちの 1 つを取り得ます。reduce
呼び出し時に、initialValue
が与えられた場合、previousValue
はinitialValue
と等しくなり、currentValue
は、配列の最初の値と等しくなります。initialValue
が与えられなかった場合、previousValue
は配列の最初の値と等しくなり、currentValue
は、2 番目の値と等しくなります。
Array.prototype.reduce() - JavaScript | MDN
やはり、第二引数を与えましょう。
[{value:1}].reduce(function(a,b){return (a.value!=null? a.value: a) + b.value},0);
// 1
callback
の引数 a
は数値で安定するため、 a.value
をチェックする必要がなくなりました。
[{value:1}].reduce(function(a,b){return a + b.value},0);
// 1
Promiseと組み合わせて非同期の直列処理を使う
async.waterfall のように、非同期処理を1つずつ実行したいときに、ES6 Promisesと組み合わせて、下記のように書けます。
// a、bの位置に注意
[1,2,3].reduce(function(promise,b){
return promise.then(function(a){
return new Promise(function(resolve){
console.log('Start task '+b);
setTimeout(function(){
console.log('End task '+b);
resolve(a + b)
},500);
});
});
},Promise.resolve(0))
.then(function(total){
console.log(total);// 6
});
resolve
で次のタスクに値を渡します。setTimeout
を、XMLHttpRequest / fetchや1、他の非同期処理などに書き換えれば、スクレイピングや、jsonの集計などに応用できます。
まとめ
初期化しようぜ
-
まともなコード載ってるページが英語しか見つけられなかった ↩