If you’re okay with mutating data, renaming an object’s key is easy.
obj = { name: 'Bobo' };
obj.somethingElse = obj.name;
delete obj.name;
If you don’t want to mutate your data, however, consider this function.
renameProp = (oldProp, newProp, { [oldProp]: old, ...others }) => ({
[newProp]: old,
...others
});
What’s happening here:
- Computed property names
- Spread syntax
- Rest params
- Destructuring assignment
Let’s add a debugger
and inspect.
renameProp = (oldProp, newProp, { [oldProp]: old, ...others }) => {
debugger;
return {
[newProp]: old,
...others
};
};
Imagine we have an object, bobo
.
bobo = {
name: 'Bobo',
job: 'Front-End Master',
age: 25
};
And we want to change bobo
’s name
to firstName
, so we plug him into renameProp
.
renameProp('name', 'firstName', bobo);
Our local variables are
oldProp
: the first parameter,'name'
newProp
: the second parameter,'firstName'
old
: A computed property name based onoldProp
. It’sbobo.name
.others
: All ofbobo
’s other properties
Let’s dive into line 4 of our code.
{ [oldProp]: old, ...others }
Dynamically find bobo’s name
Our function’s oldProp
param is ‘name’
, right? And the third parameter, the object, is bobo
, so typing bobo[oldProp]
would return bobo.name
.
The first half of line 4 uses oldProp
to find bobo
’s name and assigns it to a new variable, old
.
Gather bobo’s other properties
Now let’s focus on line 4’s other half.
Our function must change one of bobo
’s property names without mutating him, so bobo
’s other properties must remain untouched. We use spread syntax to achieve this.
Spread syntax is a beautiful shorthand for gathering bobo
’s other properties and assigning them a variable named others
.
Let’s write a similar function to cement the concept into our heads.
getPropsWithout = (names, object) =>
Object.keys(object)
.filter((key) => !names.includes(key))
.reduce(
(newObject, currentKey) => ({
...newObject,
[currentKey]: object[currentKey]
}),
{}
);
Don’t think about that function too much (unless you’re feeling adventurous! 😁). Just know that it takes an array of properties to exclude from a given object. We can use it like so:
boboNoName = getPropsWithout(['name'], bobo);
Since we’re only omitting name
, boboNoName
is identical to our others
variable that used spread syntax.
Let’s recap!
Again, our local variables are
oldProp
:‘name’
because it’s the first parameternewProp
:‘firstName’
because it’s the second parameterold
:‘Bobo’
because we dynamically assigned it using computed property names.others
:{ job: ‘Front-End Master’, age: 25 }
because we used spread syntax to dynamically assign it. (Check out my spread article! 😁)
Now let’s focus on the return
statement.
return {
[newProp]: old,
...others
};
Computed property names are being leveraged once again. We dynamically create a new object and set its firstName
to old
. It’s like writing
// remember,
// old = 'Bobo'
// newProp = 'firstName'
newBobo = {};
newBobo[newProp] = old;
// OR
newBobo.firstName = old;
Finally, we merge others
with the new object. If you’re familiar with Object.assign
, it’s just like writing
return Object.assign({}, newBobo, others);
Now bobo
has a firstName
!
And the original bobo
is left unaffected.