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[ old_key ];
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[ old_key ];
The most complete (and correct) way of doing this would be, I believe:
if (old_key !== new_key) {
Object.defineProperty(o, new_key,
Object.getOwnPropertyDescriptor(o, old_key));
delete o[old_key];
}
This method ensures that the renamed property behaves identically to the original one.
Also, it seems to me that the possibility to wrap this into a function/method and put it into Object.prototype
is irrelevant regarding your question.
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;
}
}
);
In case someone needs to rename a list of properties:
function renameKeys(obj, newKeys) {
const keyValues = Object.keys(obj).map(key => {
const newKey = newKeys[key] || key;
return { [newKey]: obj[key] };
});
return Object.assign({}, ...keyValues);
}
Usage:
const obj = { a: \"1\", b: \"2\" };
const newKeys = { a: \"A\", c: \"C\" };
const renamedObj = renameKeys(obj, newKeys);
console.log(renamedObj);
// {A:\"1\", b:\"2\"}
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];
ES6(ES2015)
way!we need keeping up with the times!
const old_obj = {
k1: `111`,
k2: `222`,
k3: `333`
};
console.log(`old_obj =\\n`, old_obj);
// {k1: \"111\", k2: \"222\", k3: \"333\"}
/**
* @author xgqfrms
* @description ES6 ...spread & Destructuring Assignment
*/
const {
k1: kA,
k2: kB,
k3: kC,
} = {...old_obj}
console.log(`kA = ${kA},`, `kB = ${kB},`, `kC = ${kC}\\n`);
// kA = 111, kB = 222, kC = 333
const new_obj = Object.assign(
{},
{
kA,
kB,
kC
}
);
console.log(`new_obj =\\n`, new_obj);
// {kA: \"111\", kB: \"222\", kC: \"333\"}
I\'d do something like this:
function renameKeys(dict, keyMap) {
return _.reduce(dict, function(newDict, val, oldKey) {
var newKey = keyMap[oldKey] || oldKey
newDict[newKey] = val
return newDict
}, {})
}
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
If you don’t want to mutate your data, consider this function...
renameProp = (oldProp, newProp, {[oldProp]:old, ...others}) => ({
[newProp]: old,
...others
})
A thorough explanation by Yazeed Bzadough https://medium.com/front-end-hacking/immutably-rename-object-keys-in-javascript-5f6353c7b6dd
Some of the solutions listed on this page have some side-effects:
Here is a solution which keeps the position of the key in the same place and is compatible in IE9+, but has to create a new object and may not be the fastest solution:
function renameObjectKey(oldObj, oldName, newName) {
const newObj = {};
Object.keys(oldObj).forEach(key => {
const value = oldObj[key];
if (key === oldName) {
newObj[newName] = value;
} else {
newObj[key] = value;
}
});
return newObj;
}
Please note: IE9 may not support forEach in strict mode
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);
Here is an example to create a new object with renamed keys.
let x = { id: \"checkout\", name: \"git checkout\", description: \"checkout repository\" };
let renamed = Object.entries(x).reduce((u, [n, v]) => {
u[`__${n}`] = v;
return u;
}, {});
Personally, the most effective way to rename keys in object without implementing extra heavy plugins and wheels:
var str = JSON.stringify(object);
str = str.replace(/oldKey/g, \'newKey\');
str = str.replace(/oldKey2/g, \'newKey2\');
object = JSON.parse(str);
You can also wrap it in try-catch
if your object has invalid structure. Works perfectly :)
This is a small modification that I made to the function of pomber; To be able to take an Array of Objects instead of an object alone and also you can activate index. also the \"Keys\" can be assigned by an array
function renameKeys(arrayObject, newKeys, index = false) {
let newArray = [];
arrayObject.forEach((obj,item)=>{
const keyValues = Object.keys(obj).map((key,i) => {
return {[newKeys[i] || key]:obj[key]}
});
let id = (index) ? {\'ID\':item} : {};
newArray.push(Object.assign(id, ...keyValues));
});
return newArray;
}
test
const obj = [{ a: \"1\", b: \"2\" }, { a: \"5\", b: \"4\" } ,{ a: \"3\", b: \"0\" }];
const newKeys = [\"A\",\"C\"];
const renamedObj = renameKeys(obj, newKeys);
console.log(renamedObj);
You can try lodash _.mapKeys
.
var user = {
name: \"Andrew\",
id: 25,
reported: false
};
var renamed = _.mapKeys(user, function(value, key) {
return key + \"_\" + user.id;
});
console.log(renamed);
<script src=\"https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js\"></script>
A variation using object destructuring and spread operator:
const old_obj = {
k1: `111`,
k2: `222`,
k3: `333`
};
// destructuring, with renaming. The variable rest will hold those values not assigned to kA, kB, or kC.
const {
k1: kA,
k2: kB,
k3: kC,
...rest
} = old_obj;
// now create a new object, with shorthand properties **kA, kB, kC**;
// spread the remaining properties in the **rest** variable
const newObj = {kA, kB, kC, ...rest};