Is there a clever (i.e. optimized) way to rename a key in a javascript object?
A non-optimized way would be:
o[ new_key ] = o[ old_key ];
delete o[ o
If you're mutating your source object, ES6 can do it in one line.
delete Object.assign(o, {[newKey]: o[oldKey] })[oldKey];
Or two lines if you want to create a new object.
const newObject = {};
delete Object.assign(newObject, o, {[newKey]: o[oldKey] })[oldKey];
I would say that it would be better from a conceptual point of view to just leave the old object (the one from the web service) as it is, and put the values you need in a new object. I'm assuming you are extracting specific fields at one point or another anyway, if not on the client, then at least on the server. The fact that you chose to use field names that are the same as those from the web service, only lowercase, doesn't really change this. So, I'd advise to do something like this:
var myObj = {
field1: theirObj.FIELD1,
field2: theirObj.FIELD2,
(etc)
}
Of course, I'm making all kinds of assumptions here, which may not be true. If this doesn't apply to you, or if it's too slow (is it? I haven't tested, but I imagine the difference gets smaller as the number of fields increases), please ignore all of this :)
If you don't want to do this, and you only have to support specific browsers, you could also use the new getters to also return "uppercase(field)": see http://robertnyman.com/2009/05/28/getters-and-setters-with-javascript-code-samples-and-demos/ and the links on that page for more information.
EDIT:
Incredibly, this is also almost twice as fast, at least on my FF3.5 at work. See: http://jsperf.com/spiny001
Yet another way with the most powerful REDUCE method.
data = {key1: "value1", key2: "value2", key3: "value3"};
keyMap = {key1: "firstkey", key2: "secondkey", key3: "thirdkey"};
mappedData = Object.keys(keyMap).reduce((obj,k) => Object.assign(obj, { [keyMap[k]]: data[k] }),{});
console.log(mappedData);
To add prefix to each key:
const obj = {foo: 'bar'}
const altObj = Object.fromEntries(
Object.entries(obj).map(([key, value]) =>
// Modify key here
[`x-${key}`, value]
)
)
// altObj = {'x-foo': 'bar'}
You could wrap the work in a function and assign it to the Object
prototype. Maybe use the fluent interface style to make multiple renames flow.
Object.prototype.renameProperty = function (oldName, newName) {
// Do nothing if the names are the same
if (oldName === newName) {
return this;
}
// Check for the old property name to avoid a ReferenceError in strict mode.
if (this.hasOwnProperty(oldName)) {
this[newName] = this[oldName];
delete this[oldName];
}
return this;
};
ECMAScript 5 Specific
I wish the syntax wasn't this complex but it is definitely nice having more control.
Object.defineProperty(
Object.prototype,
'renameProperty',
{
writable : false, // Cannot alter this property
enumerable : false, // Will not show up in a for-in loop.
configurable : false, // Cannot be deleted via the delete operator
value : function (oldName, newName) {
// Do nothing if the names are the same
if (oldName === newName) {
return this;
}
// Check for the old property name to
// avoid a ReferenceError in strict mode.
if (this.hasOwnProperty(oldName)) {
this[newName] = this[oldName];
delete this[oldName];
}
return this;
}
}
);
While this does not exactly give a better solution to renaming a key, it provides a quick and easy ES6 way to rename all keys in an object while not mutating the data they contain.
let b = {a: ["1"], b:["2"]};
Object.keys(b).map(id => {
b[`root_${id}`] = [...b[id]];
delete b[id];
});
console.log(b);