この翻訳は不完全です。英語から この記事を翻訳 してください。

reduce() はアキュムレータと配列の各要素に対して(左から右へ)関数を適用し、単一の値にします。

reducer関数には以下の4つのパラメータが与えられます。

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

reducer関数の戻り値はアキュムレータに渡され、配列内の各イテレーションに対してこの値を記憶します。最終的に単一の値になります。

構文

arr.reduce(callback[, initialValue])

引数

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

戻り値

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

詳細

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

  • accumulator
  • currentValue
  • currentIndex
  • array

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

Note: 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 );

How reduce() works

次のコードのように 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() の 第二引数に初期値を設定した場合は、コールバック各回の内部的な動作はこのようになります。

[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 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),
  []
);

Counting instances of values in an object

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 }

Bonding arrays contained in an array of objects using the spread operator and 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'
// ]

 

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

let arr = [1, 2, 1, 2, 3, 5, 4, 5, 3, 4, 4, 4, 4];
let result = arr.sort().reduce((accumulator, current) => {
    const length = accumulator.length
    if (length === 0 || accumulator[length - 1] !== current) {
        accumulator.push(current);
    }
    return accumulator;
}, []);
console.log(result); //[1,2,3,4,5]

Running Promises in Sequence

/**
 * Runs promises from promise array in chained manner
 *
 * @param {array} arr - promise arr
 * @return {Object} promise object
 */
function runPromiseInSequense(arr) {
  return arr.reduce((promiseChain, currentPromise) => {
    return promiseChain.then((chainedResult) => {
      return currentPromise(chainedResult)
        .then((res) => res)
    })
  }, Promise.resolve());
}

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

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

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

const promiseArr = [p1, p2, p3];
runPromiseInSequense(promiseArr)
  .then((res) => {
    console.log(res);   // 30
  });

 

Function composition enabling piping

// 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

ポリフィル

// 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;
    }
  });
}

If you need to support truly obsolete JavaScript engines that don't support Object.defineProperty(), it's best not to polyfill Array.prototype methods at all, as you can't make them non-enumerable.

Specifications

Specification Status Comment
ECMAScript 5.1 (ECMA-262)
Array.prototype.reduce() の定義
標準 Initial definition. Implemented in 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
基本対応Chrome 完全対応 ありEdge 完全対応 ありFirefox 完全対応 3IE 完全対応 9Opera 完全対応 10.5Safari 完全対応 4WebView Android 完全対応 ありChrome Android 完全対応 ありEdge Mobile 完全対応 ありFirefox Android 完全対応 4Opera Android 完全対応 ありSafari iOS 完全対応 ありSamsung Internet Android 完全対応 ありnodejs 完全対応 あり

凡例

完全対応  
完全対応

関連情報

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

このページの貢献者: elkurin, yuna, sunvisor, mizozobu, woodmix, uknmr, teoli, ethertank, Mgjbot, Potappo
最終更新者: elkurin,