Alternatives to Spread Operator Reduce


Here are some alternative options to using the spread operator in an array reduce.

Scenario

Let's say that I have an array of objects:

const arr = [
  { key: 'c', value: 33 },
  { key: 'b', value: 2 },
  { key: 'a', value: 44 },
  { key: 'a', value: 1 },
  { key: 'c', value: 3 },
]

And you want to transform it into an object where the key field is the key and the value is the last object in the array with that key in the array. That data structure would look like this:

{
  a: { key: 'a', value: 1 },
  b: { key: 'b', value: 2 },
  c: { key: 'c', value: 3 },
}

So what are our options to make that transformation?

Spread Operator in Reduce

The most readable option is the spread operator. It's clean and the intent is clear:

arr.reduce((acc, [key, value]) => {
  return {
    ...acc,
    [key]: value
  }
}, {})

The problem is that the spread operator is slow.

Alternative?

Modify in Place

Don't spread and re-create the accumulator. Modify it in place. Is that so bad? It can be. But this is local, not shared, state. And it's a small function where the only operation is modification, so ordering is not a problem. But beware, as soon as you modify state, you open yourself to a class of modification bugs. It's often better to just avoid it.

arr.reduce((acc, [key, value]) => {
  acc[key] = value
  return acc
}, {})

Map and Create Object

Is there a way to avoid modification and the spread operator? Here's one way: Use Array.map, then Object.fromEntries:

Object.fromEntries(arr.map(({ key, value }) => [key, value]))

Note that Object.fromEntries requires as input an array of arrays. It's a bit more convoluted, but not bad. Supposedly it's faster.

Is there another option that you like? Are the options worth the readability downgrades from using the spread operator?