reduce() は配列の各要素に対して(引数で与えられた)reducer 関数を実行して、単一の値にします。

reducer 関数は 4 つの引数を取り込みます。

  1. アキュムレータ (acc)
  2. 現在値 (cur)
  3. 現在のインデックス (idx)
  4. ソースの配列 (src)

reducer 関数の戻り値はアキュムレータに代入され、配列内の各反復に対してこの値を記憶します。最終的に単一の値になります。

構文

arr.reduce(callback[, initialValue])

引数

callback
次の 4 つの引数を取って、配列内の各要素に対し実行されるコールバック関数です。
accumulator
コールバックの戻り値を累積します。累積値は、ひとつ前の戻り値、もしくは initialValue です。initialValue については、後で述べます。
currentValue
現在処理されている配列の要素です。
currentIndex Optional
現在処理されている配列要素のインデックスです。initialValue が指定された場合はインデックス 0 から、そうでない場合はインデックス 1 から開始します。
array Optional
reduce() が呼ばれた配列です。
initialValue Optional
callback の最初の呼び出しのときに、最初の引数として使用されます。設定しなかった場合、配列の最初の要素が使用されます。空の配列を initialValue なしで実行するとエラーになります。

戻り値

畳み込みによって得られた値です。

詳細

reduce() は、配列に存在する各要素に対して、callback 関数を一度だけ実行します。配列の欠けている部分は対象から外されます。また callback 関数には次の 4 つの引数が渡されます。

  • accumulator
  • currentValue
  • currentIndex
  • array

コールバックが初めて呼び出されるときは、accumulatorcurrentValue は次の 2 つの値のうちの 1 つになります。reduce() の呼び出しで initialValue が指定された場合、accumulatorinitialValue と等しくなり、currentValue は配列の最初の値と等しくなります。initialValue が指定されていない場合は、accumulator は配列の最初の値と等しくなり、currentValue は 2 番目の値と等しくなります。

注: initialValue が指定されなかった場合は、reduce() は最初のインデックスを飛ばしてインデックス 1 から実行されます。initialValue が指定されていたらインデックス 0 から開始します。

空配列で initialValue が指定されなかった場合、TypeError が発生します。配列が 1 つの要素しか持たず initialValue が指定されなかった場合、または initialValue が指定されていても空配列の場合、callback が実行されず要素が返却されます。

initialValue を指定しない場合、下記の例のような 3 種類の結果が発生しうるため、初期値を指定する方が通常は安全です。

var maxCallback = ( acc, cur ) => Math.max( acc.x, cur.x );
var maxCallback2 = ( max, cur ) => Math.max( max, cur );

// reduce() without initialValue
[ { x: 22 }, { x: 42 } ].reduce( maxCallback ); // 42
[ { x: 22 }            ].reduce( maxCallback ); // { x: 22 }
[                      ].reduce( maxCallback ); // TypeError

// map/reduce; better solution, also works for empty or larger arrays
[ { x: 22 }, { x: 42 } ].map( el => el.x )
                        .reduce( maxCallback2, -Infinity );

reduce() はどう動くか

次のコードのように reduce() を使用した場合について見てみましょう。

[0, 1, 2, 3, 4].reduce(function(accumulator, currentValue, currentIndex, array) {
  return accumulator + currentValue;
});

コールバック関数は 4 回呼び出され、各回の引数の内容は以下のようになっています。

callback accumulator currentValue currentIndex array 戻り値
初回の呼出し 0 1 1 [0, 1, 2, 3, 4] 1
2 回目の呼出し 1 2 2 [0, 1, 2, 3, 4] 3
3 回目の呼出し 3 3 3 [0, 1, 2, 3, 4] 6
4 回目の呼出し 6 4 4 [0, 1, 2, 3, 4] 10

reduce() の戻り値は、コールバック関数の最後の戻り値である (10)となるでしょう。

通常の関数の代わりにアロー関数を指定できます。下記のコードは上述のコードと同じ結果を返します。

[0, 1, 2, 3, 4].reduce( (accumulator, currentValue) => accumulator + currentValue );

reduce() の 2 つ目の引数に初期値を設定した場合は、コールバック各回の内部的な動作はこのようになります。

[0, 1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => {
    return accumulator + currentValue;
}, 10);
callback accumulator currentValue currentIndex array 戻り値
初回の呼出し 10 0 0 [0, 1, 2, 3, 4] 10
2 回目の呼出し 10 1 1 [0, 1, 2, 3, 4] 11
3 回目の呼出し 11 2 2 [0, 1, 2, 3, 4] 13
4 回目の呼出し 13 3 3 [0, 1, 2, 3, 4] 16
5 回目の呼出し 16 4 4 [0, 1, 2, 3, 4] 20

reduce() の戻り値はもちろん 20 となります。

配列内の値の合計値を出す

var sum = [0, 1, 2, 3].reduce(function (accumulator, currentValue) {
  return accumulator + currentValue;
}, 0);
// sum is 6

また、アロー関数を用いて書くことも出来ます。

var total = [ 0, 1, 2, 3 ].reduce(
  ( accumulator, currentValue ) => accumulator + currentValue,
  0
);

オブジェクトの配列の値の合計値を出す

オブジェクトの配列に含まれた値の合計値を出すには、すべての項目を関数内で取得できるようにするために初期値を指定する必要があります

var initialValue = 0;
var sum = [{x: 1}, {x: 2}, {x: 3}].reduce(function (accumulator, currentValue) {
    return accumulator + currentValue.x;
},initialValue)

console.log(sum) // logs 6

また、アロー関数を用いて書くことも出来ます。

var initialValue = 0;
var sum = [{x: 1}, {x: 2}, {x: 3}].reduce(
    (accumulator, currentValue) => accumulator + currentValue.x
    ,initialValue
);

console.log(sum) // logs 6

二次元配列を一次元配列にする

var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
  function(accumulator, currentValue) {
    return accumulator.concat(currentValue);
  },
  []
);
// flattened is [0, 1, 2, 3, 4, 5]

また、アロー関数を用いて書くことも出来ます。

var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
  ( accumulator, currentValue ) => accumulator.concat(currentValue),
  []
);

オブジェクトの値のインスタンスを数える

var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];

var countedNames = names.reduce(function (allNames, name) { 
  if (name in allNames) {
    allNames[name]++;
  }
  else {
    allNames[name] = 1;
  }
  return allNames;
}, {});
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }

プロパティによってオブジェクトをグループ化する

var people = [
  { name: 'Alice', age: 21 },
  { name: 'Max', age: 20 },
  { name: 'Jane', age: 20 }
];

function groupBy(objectArray, property) {
  return objectArray.reduce(function (acc, obj) {
    var key = obj[property];
    if (!acc[key]) {
      acc[key] = [];
    }
    acc[key].push(obj);
    return acc;
  }, {});
}

var groupedPeople = groupBy(people, 'age');
// groupedPeople is:
// { 
//   20: [
//     { name: 'Max', age: 20 }, 
//     { name: 'Jane', age: 20 }
//   ], 
//   21: [{ name: 'Alice', age: 21 }] 
// }

スプレッド演算子と initialValue を使ってオブジェクトの配列に含まれる配列を結合させる

// friends - an array of objects 
// where object field "books" - list of favorite books 
var friends = [{
  name: 'Anna',
  books: ['Bible', 'Harry Potter'],
  age: 21
}, {
  name: 'Bob',
  books: ['War and peace', 'Romeo and Juliet'],
  age: 26
}, {
  name: 'Alice',
  books: ['The Lord of the Rings', 'The Shining'],
  age: 18
}];

// allbooks - list which will contain all friends' books +  
// additional list contained in initialValue
var allbooks = friends.reduce(function(accumulator, currentValue) {
  return [...accumulator, ...currentValue.books];
}, ['Alphabet']);

// allbooks = [
//   'Alphabet', 'Bible', 'Harry Potter', 'War and peace', 
//   'Romeo and Juliet', 'The Lord of the Rings',
//   'The Shining'
// ]

配列内の重複要素を除去する

注: Set と Array.from() に対応している環境を使っている場合、重複要素を除去された配列を let orderedArray = Array.from(new Set(myArray));  を使うことで取得できます。

var myArray = ['a', 'b', 'a', 'b', 'c', 'e', 'e', 'c', 'd', 'd', 'd', 'd'];
var myOrderedArray = myArray.reduce(function (accumulator, currentValue) {
  if (accumulator.indexOf(currentValue) === -1) {
    accumulator.push(currentValue);
  }
  return accumulator
}, [])

console.log(myOrderedArray);

シーケンス上の Promise を動かす

/**
 * Runs promises from array of functions that can return promises
 * in chained manner
 *
 * @param {array} arr - promise arr
 * @return {Object} promise object
 */
function runPromiseInSequence(arr, input) {
  return arr.reduce(
    (promiseChain, currentFunction) => promiseChain.then(currentFunction),
    Promise.resolve(input)
  );
}

// promise function 1
function p1(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 5);
  });
}

// promise function 2
function p2(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 2);
  });
}

// function 3  - will be wrapped in a resolved promise by .then()
function f3(a) {
 return a * 3;
}

// promise function 4
function p4(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 4);
  });
}

const promiseArr = [p1, p2, f3, p4];
runPromiseInSequence(promiseArr, 10)
  .then(console.log);   // 1200

パイプによって関数を合成する

// Building-blocks to use for composition
const double = x => x + x;
const triple = x => 3 * x;
const quadruple = x => 4 * x;

// Function composition enabling pipe functionality
const pipe = (...functions) => input => functions.reduce(
    (acc, fn) => fn(acc),
    input
);

// Composed functions for multiplication of specific values
const multiply6 = pipe(double, triple);
const multiply9 = pipe(triple, triple);
const multiply16 = pipe(quadruple, quadruple);
const multiply24 = pipe(double, triple, quadruple);

// Usage
multiply6(6); // 36
multiply9(9); // 81
multiply16(16); // 256
multiply24(10); // 240

reduce を使って map メソッドを書く

if (!Array.prototype.mapUsingReduce) {
  Array.prototype.mapUsingReduce = function(callback, thisArg) {
    return this.reduce(function(mappedArray, currentValue, index, array) {
      mappedArray[index] = callback.call(thisArg, currentValue, index, array);
      return mappedArray;
    }, []);
  };
}

[1, 2, , 3].mapUsingReduce(
  (currentValue, index, array) => currentValue + index + array.length
); // [5, 7, , 10]

ポリフィル

// Production steps of ECMA-262, Edition 5, 15.4.4.21
// Reference: http://es5.github.io/#x15.4.4.21
// https://tc39.github.io/ecma262/#sec-array.prototype.reduce
if (!Array.prototype.reduce) {
  Object.defineProperty(Array.prototype, 'reduce', {
    value: function(callback /*, initialValue*/) {
      if (this === null) {
        throw new TypeError( 'Array.prototype.reduce ' + 
          'called on null or undefined' );
      }
      if (typeof callback !== 'function') {
        throw new TypeError( callback +
          ' is not a function');
      }

      // 1. Let O be ? ToObject(this value).
      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0; 

      // Steps 3, 4, 5, 6, 7      
      var k = 0; 
      var value;

      if (arguments.length >= 2) {
        value = arguments[1];
      } else {
        while (k < len && !(k in o)) {
          k++; 
        }

        // 3. If len is 0 and initialValue is not present,
        //    throw a TypeError exception.
        if (k >= len) {
          throw new TypeError( 'Reduce of empty array ' +
            'with no initial value' );
        }
        value = o[k++];
      }

      // 8. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kPresent be ? HasProperty(O, Pk).
        // c. If kPresent is true, then
        //    i.  Let kValue be ? Get(O, Pk).
        //    ii. Let accumulator be ? Call(
        //          callbackfn, undefined,
        //          « accumulator, kValue, k, O »).
        if (k in o) {
          value = callback(value, o[k], k, o);
        }

        // d. Increase k by 1.      
        k++;
      }

      // 9. Return accumulator.
      return value;
    }
  });
}

Object.defineProperty() をサポートしていない、本当に古い JavaScript エンジンをサポートする必要がある場合、列挙不可に設定することができないため、すべての Array.prototype メソッドは polyfill されないべきです。

仕様

仕様書 策定状況 コメント
ECMAScript 5.1 (ECMA-262)
Array.prototype.reduce() の定義
標準 初期定義です。 JavaScript 1.8 で実装されました。
ECMAScript 2015 (6th Edition, ECMA-262)
Array.prototype.reduce() の定義
標準  
ECMAScript Latest Draft (ECMA-262)
Array.prototype.reduce() の定義
ドラフト  

ブラウザー実装状況

Update compatibility data on GitHub
デスクトップモバイルサーバー
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeEdge MobileAndroid 版 FirefoxAndroid 版 OperaiOSのSafariSamsung InternetNode.js
reduceChrome 完全対応 ありEdge 完全対応 12Firefox 完全対応 3IE 完全対応 9Opera 完全対応 10.5Safari 完全対応 4WebView Android 完全対応 ありChrome Android 完全対応 ありEdge Mobile 完全対応 ありFirefox Android 完全対応 4Opera Android 完全対応 ありSafari iOS 完全対応 ありSamsung Internet Android 完全対応 ありnodejs 完全対応 あり

凡例

完全対応  
完全対応

関連情報

ドキュメントのタグと貢献者

最終更新者: mdnwebdocs-bot,