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

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

構文

arr.reduce(callback[, initialValue])

引数

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

Return value

The value that results from the reduction.

詳細

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

  • accumulator
  • currentValue
  • currentIndex
  • array

The first time the callback is called, accumulator and currentValue can be one of two values. If initialValue is provided in the call to reduce(), then accumulator will be equal to initialValue, and currentValue will be equal to the first value in the array. If no initialValue is provided, then accumulator will be equal to the first value in the array, and currentValue will be equal to the second.

Note: If initialValue isn't provided, reduce() will execute the callback function starting at index 1, skipping the first index. If initialValue is provided, it will start at index 0.

If the array is empty and no initialValue is provided, TypeError will be thrown. If the array has only one element (regardless of position) and no initialValue is provided, or if initialValue is provided but the array is empty, the solo value will be returned without calling callback.

It is usually safer to provide an initial value because there are three possible outputs without initialValue, as shown in the following example.

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)となるでしょう。

You can also provide an Arrow Function in lieu of a full function. The code below will produce the same output as the code in the block above:

[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

Alternatively, written with an arrow function:

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

 

Remove duplicate items in array

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() の定義
ドラフト  

ブラウザ実装状況

機能ChromeEdgeFirefoxInternet ExplorerOperaSafari
基本対応 あり あり3910.54
機能Android webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
基本対応 あり あり あり4 あり あり あり

関連情報

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

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