19
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Array.prototype.reduce の第二引数で sum 値を初期化しましょうという話

Last updated at Posted at 2015-07-05
[1,2,3].reduce(function(a,b){return a + b});// 6

sum(配列の合計を求め)るとき、reduceを使うと便利ですが、いくつか注意すべき点があります。

.length0 で失敗

空の配列に.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 つ前の要素。もしくは、initialValueinitialValue > については、後で述べます。
currentValue
現在処理されている配列要素
index
現在処理されている配列要素のインデックス
array
reduce に呼ばれた配列
initialValue
callback の最初の呼び出しのときに、最初の実引数として用いるためのオブジェクト。
関数が呼び出される初回は、 previousValuecurrentValue は 2 つの値のうちの 1 つを取り得ます。reduce 呼び出し時に、initialValue が与えられた場合、previousValueinitialValue と等しくなり、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 / fetch1、他の非同期処理などに書き換えれば、スクレイピングや、jsonの集計などに応用できます。

参考: コレクションのバカ騒ぎ | Promiseアンチパターン - くじら公園

まとめ

初期化しようぜ

  1. まともなコード載ってるページが英語しか見つけられなかった

19
14
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?