30 Seconds of Code is a brilliant collection of JavaScript snippets, digestible in ≤ 30 seconds. Anyone looking to master JavaScript should go through the entire thing.

The list didn’t contain a function to rename multiple object keys, however, so I created a pull request that thankfully got merged!

Here’s the official entry: https://30secondsofcode.org/object#renamekeys

I’ve previously written on renaming object keys, but we only changed one key at a time.

Then Adam Rowe kindly commented, asking how we might rename multiple object keys. I replied with this code sample after some thought and research.

renameKeys = (keysMap, obj) =>
  Object.keys(obj).reduce(
    (acc, key) => ({
      ...acc,
      ...{ [keysMap[key] || key]: obj[key] }
    }),
    {}
  );

This was inspired by Ramda Adjunct’s renameKeys function.

  • keysMap contains key/value pairs of your old/new object keys.
  • obj is the object to be changed.

You might use it like this:

keysMap = {
  name: 'firstName',
  job: 'passion'
};

obj = {
  name: 'Bobo',
  job: 'Front-End Master'
};

renameKeys(keysMap, obj);
// { firstName: 'Bobo', passion: 'Front-End Master' }

Let’s step through it! We can write an expanded, debugger-friendly version of this function:

renameKeys = (keysMap, obj) => {
  debugger;

  return Object.keys(obj).reduce((acc, key) => {
    debugger;

    const renamedObject = {
      [keysMap[key] || key]: obj[key]
    };

    debugger;

    return {
      ...acc,
      ...renamedObject
    };
  }, {});
};

And we’ll use it like this:

renameKeys(
  {
    name: 'firstName',
    job: 'passion'
  },
  {
    name: 'Bobo',
    job: 'Front-End Master'
  }
);

1*C9BI6jfACst-UcchX6wyyA

Pausing on line 2, we see that keysMap and obj have been properly assigned.

Here’s where the fun begins. Move to the next debugger.

1*3HKJjlIj8tChHNlre9WV9Q

Inspect our local variables on line 7:

  • acc: {} because that’s Array.reduce()’s initial value (line 19).
  • key: “name” because it’s the first key from Object.keys(obj).
  • renamedObject: undefined

Also notice that we can access keysMap and obj from the parent function’s scope.

Guess what renamedObject will be. Like in my aforementioned post, we’re using computed property names to dynamically assign renamedObject's key.

If keysMap[key] exists, use it. Otherwise, use the original object key. In this case, keysMap[key] is “firstName”.

1*aYI7ss4IOWIipNsC40r9rg

That’s renamedObject's key, what about its corresponding value?

1*GEBIVtNMWIuosMVq4FLMQw

It’s obj[key]: "Bobo". Hit the next debugger and check it out.

1*XMGM2FxuNscmq_imZf8Nmw

renamedObject is now { firstName: “Bobo” }.

1*z8HEVhgr8-e5HFrtAK5lzg

Now using the spread operator, we’ll merge acc and renamedObject. Remember that acc is currently .reduce's initial value: an empty object.

So merging acc and renamedObject just results in a clone of renamedObject.

1*Fw0QyV7VsU2UH-GtD-74WQ

Since we’re returning this object, however, it becomes acc in .reduce’s next iteration. Move to the next debugger to see this.

1*h0Lxhtw1trErPruUBKamfA

We’re inside .reduce's again, because there’s one more key to process. We see that acc is now { firstName: "Bobo" }.

The same process runs again, and renamedObject is properly created.

1*OfKamMrGJLBIvY2WgQrlaA

This time, merging acc and renamedObject actually makes a difference.

1*uMdN7mSsIhgvzJCceftUOw

Run past this debugger to return that object, and you’re done!

Here’s the final output:

1*TpcJHEG6MUxazCkNnCg6AQ

Have fun renaming all the keys, until next time!