つよつよエンジニアになりたい

つよつよエンジニアになりたいエンジニアが日々の学びや気づきをアウトプットしていきます

JSのreduceの使い方をおさらいする

たまにreduceに遭遇して使い方がパッと出てこなかったのでおさらいします。

引数

  • callbackFnc
    • previousValue
    • currentValue
    • currentIndex
    • array
  • initialValue

reduceは直前のコールバック関数の計算結果を返します。コールバック関数の最初は直前の計算結果はないためreduceの第二引数に初期値を渡します。 第二引数を省略した場合は配列の要素の0番目が初期値となります。 prevとcurrの合計が次のprevの値となっていることがわかります。

// 初期値がある場合
const array = [1,2,3,4,5];
const result = array.reduce((prev, curr, idx) => {
    console.log(`prev: ${prev}, curr: ${curr}, idx: ${idx}`);
    return prev+curr;
}, 100);
console.log(`result: ${result}`);

// prev: 100, curr: 1, idx: 0
// prev: 101, curr: 2, idx: 1
// prev: 103, curr: 3, idx: 2
// prev: 106, curr: 4, idx: 3
// prev: 110, curr: 5, idx: 4
// result: 115

下の例では最初のprevはarray[0]の1となります。

// 初期値がない場合
const array = [1,2,3,4,5];
const result = array.reduce((prev, curr, idx) => {
    console.log(`prev: ${prev}, curr: ${curr}, idx: ${idx}`);
    return prev+curr;
});
console.log(`result: ${result}`);

// prev: 1, curr: 2, idx: 1
// prev: 3, curr: 3, idx: 2
// prev: 6, curr: 4, idx: 3
// prev: 10, curr: 5, idx: 4
// result: 15

コールバック関数で値を返さないと次のコールバック関数の処理でpreviousValueはundefinedとなります。

コールバック関数内で配列を変更した場合

配列変更時の動作についてはMDNで以下のように記述されていました。

・もし reduce() が配列に対して反復処理を始めた後に配列に要素が追加された場合、コールバック関数は追加された要素に対して反復処理を行いません。

・配列の既存の要素が変更された場合、コールバック関数に渡される値は、reduce()が配列に対して最初に呼び出された時点の値になります。

・reduce() の呼び出しが始まった後、反復処理される前に削除された配列要素は reduce() の処理が行われません。

文章だけではよくわからなかったのでコードを書いて試してみました。

コールバック関数内で配列に要素を追加しても追加された要素に対して処理はされないようです。処理が終わった後に元の配列を確認すると要素が追加されていることがわかります。

const array = [1,2,3,4,5];
const result = array.reduce((prev, curr, idx, arr) => {
    arr.push(100); // 要素を追加
    console.log(`prev: ${prev}, curr: ${curr}, idx: ${idx}`);
    return prev+curr;
});
console.log(`result: ${result}`);
console.log(array);

// prev: 1, curr: 2, idx: 1
// prev: 3, curr: 3, idx: 2
// prev: 6, curr: 4, idx: 3
// prev: 10, curr: 5, idx: 4
// result: 15
// [1, 2, 3, 4, 5, 100, 100, 100, 100]

コールバック関数内で要素を削除すると削除された要素の分だけ反復処理が減っていることがわかります。

const array = [1,2,3,4,5];
const result = array.reduce((prev, curr, idx, arr) => {
    arr.pop(); // 要素を削除
    console.log(`prev: ${prev}, curr: ${curr}, idx: ${idx}`);
    return prev+curr;
});
console.log(`result: ${result}`);
console.log(array);

// prev: 1, curr: 2, idx: 1
// prev: 3, curr: 3, idx: 2
// result: 6
// [1, 2]

参考

Array.prototype.reduce() - JavaScript | MDN