【JavaScript】reduce(Object.assign)で失敗した
コレクションの配列をオブジェクトにしようとして、こんな感じのコードをよく書くのだけど、
const users = [{ id: 1, name: 'suzuki' }, { id: 2, name: 'sato' }] const usersById = users .map((user) => ({[user.id]: user})) .reduce((obj, userObj) => Object.assign(obj, userObj), {}) console.log(usersById) // { '1': { id: 1, name: 'suzuki' }, // '2': { id: 2, name: 'sato' } }
ふと、reduceに適用している関数は Object.assign
なんだからこう書けるんじゃないかと思ったけど、
const usersById = users .map((user) => ({[user.id]: user})) .reduce(Object.assign, {})
なんと意図した動きにならなかった。実行結果がこうなる。
const usersById = users .map((user) => ({[user.id]: user})) .reduce(Object.assign, {}) console.log(usersById) // { '0': { '1': { id: 1, name: 'suzuki' } }, // '1': { '2': { id: 2, name: 'sato' } }, // '2': { id: 2, name: 'sato' } }
理由は、reduce
の仕様にある。
reduce
のコールバックに与える関数には4つの引数を与える。
- previousValue - 現在処理されている配列要素の 1 つ前の要素。もしくは、initialValue。
- currentValue - 現在処理されている配列要素
- index - 現在処理されている配列要素のインデックス
- array - reduce に呼ばれた配列
なので、Object.assign
をそのままコールバック関数に与えると、Object.assign(previousValue, currentValue, index, array)
を実行してしまう。それで上記のような思わぬ結果になった。
結論としては、 array.reduce(Object.assign, {})
としてはいけない。