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 ]; 1634 Answers
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.
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]; 10You 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; } } ); 9In 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"} 2I would like just using the 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"}4To 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'} 1If 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
Here is a typescript friendly version:
// These generics are inferred, do not pass them in. export const renameKey = < OldKey extends keyof T, NewKey extends string, T extends Record<string, unknown> >( oldKey: OldKey, newKey: NewKey extends keyof T ? never : NewKey, userObject: T ): Record<NewKey, T[OldKey]> & Omit<T, OldKey> => { const { [oldKey]: value, ...common } = userObject return { ...common, ...({ [newKey]: value } as Record<NewKey, T[OldKey]>) } } It will prevent you from clobbering an existing key or renaming it to the same thing
2A 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 the renamed properties kA, kB, kC; // spread the remaining original properties in the 'rest' variable const newObj = {kA, kB, kC, ...rest}; For one key, this can be as simple as:
const { k1: kA, ...rest } = old_obj; const new_obj = { kA, ...rest } You may also prefer a more 'traditional' style:
const { k1, ...rest } = old_obj const new_obj = { kA: k1, ...rest} 3Most of the answers here fail to maintain JS Object key-value pairs order. If you have a form of object key-value pairs on the screen that you want to modify, for example, it is important to preserve the order of object entries.
The ES6 way of looping through the JS object and replacing key-value pair with the new pair with a modified key name would be something like:
let newWordsObject = {}; Object.keys(oldObject).forEach(key => { if (key === oldKey) { let newPair = { [newKey]: oldObject[oldKey] }; newWordsObject = { ...newWordsObject, ...newPair } } else { newWordsObject = { ...newWordsObject, [key]: oldObject[key] } } }); The solution preserves the order of entries by adding the new entry in the place of the old one.
1You 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=""></script>1Personally, 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 :)
Rename Key but Avoid changing original Objects parameters
oldJson=[{firstName:'s1',lastName:'v1'}, {firstName:'s2',lastName:'v2'}, {firstName:'s3',lastName:'v3'}] newJson = oldJson.map(rec => { return { 'Last Name': rec.lastName, 'First Name': rec.firstName, } }) output: [{Last Name:"v1",First Name:"s1"}, {Last Name:"v2",First Name:"s2"}, {Last Name:"v3",First Name:"s3"}] better to have a new array
1I'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 }, {}) } 1Yet 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); // { "firstkey": "value1", "secondkey": "value2", "thirdkey": "value3"}just try it in your favorite editor <3
const obj = {1: 'a', 2: 'b', 3: 'c'} const OLD_KEY = 1 const NEW_KEY = 10 const { [OLD_KEY]: replaceByKey, ...rest } = obj const new_obj = { ...rest, [NEW_KEY]: replaceByKey } 2I 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 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:
1While 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); 2If you want to retain the iteration order (order of insertion), here is a suggestion:
const renameObjectKey = (object, oldName, newName) => { const updatedObject = {} for(let key in object) { if (key === oldName) { newObject[newName] = object[key] } else { newObject[key] = object[key] } } object = updatedObject } 0Some of the solutions listed on this page have some side-effects:
- affect the position of the key in the object, adding it to the bottom (if this matters to you)
- would not work in IE9+ (again, if this matters to you)
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
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; }, {}); 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); Your way is optimized, in my opinion. But you will end up with reordered keys. Newly created key will be appended at the end. I know you should never rely on key order, but if you need to preserve it, you will need to go through all keys and construct new object one by one, replacing the key in question during that process.
Like this:
var new_o={}; for (var i in o) { if (i==old_key) new_o[new_key]=o[old_key]; else new_o[i]=o[i]; } o=new_o; 0- You can use a utility to handle this.
npm i paix import { paix } from 'paix'; const source_object = { FirstName: "Jhon", LastName: "Doe", Ignored: true }; const replacement = { FirstName: 'first_name', LastName: 'last_name' }; const modified_object = paix(source_object, replacement); console.log(modified_object); // { Ignored: true, first_name: 'Jhon', last_name: 'Doe' }; Trying using lodash transform.
var _ = require('lodash'); obj = { "name": "abc", "add": "xyz" }; var newObject = _.transform(obj, function(result, val, key) { if (key === "add") { result["address"] = val } else { result[key] = val } }); console.log(obj); console.log(newObject); const clone = (obj) => Object.assign({}, obj); const renameKey = (object, key, newKey) => { const clonedObj = clone(object); const targetKey = clonedObj[key]; delete clonedObj[key]; clonedObj[newKey] = targetKey; return clonedObj; }; let contact = {radiant: 11, dire: 22}; contact = renameKey(contact, 'radiant', 'aplha'); contact = renameKey(contact, 'dire', 'omega'); console.log(contact); // { aplha: 11, omega: 22 }; Would there be any problem with simply doing this?
someObject = {...someObject, [newKey]: someObject.oldKey} delete someObject.oldKey Which could be wrapped in a function, if preferred:
const renameObjectKey = (object, oldKey, newKey) => { // if keys are the same, do nothing if (oldKey === newKey) return; // if old key doesn't exist, do nothing (alternatively, throw an error) if (!object.oldKey) return; // if new key already exists on object, do nothing (again - alternatively, throw an error) if (object.newKey !== undefined) return; object = { ...object, [newKey]: object[oldKey] }; delete object[oldKey]; return { ...object }; }; // in use let myObject = { keyOne: 'abc', keyTwo: 123 }; // avoids mutating original let renamed = renameObjectKey(myObject, 'keyTwo', 'renamedKey'); console.log(myObject, renamed); // myObject /* { "keyOne": "abc", "keyTwo": 123, } */ // renamed /* { "keyOne": "abc", "renamedKey": 123, } */ My way, adapting the good @Mulhoon typescript post, for changing multiple keys :
const renameKeys = < TOldKey extends keyof T, TNewkey extends string, T extends Record<string, unknown> >( keys: {[ key: string]: TNewkey extends TOldKey ? never : TNewkey }, obj: T ) => Object .keys(obj) .reduce((acc, key) => ({ ...acc, ...{ [keys[key] || key]: obj[key] } }), {}); renameKeys({id: 'value', name: 'label'}, {id: 'toto_id', name: 'toto', age: 35}); Another way to rename Object Key:
Let's consider this object:
let obj = {"name": "John", "id": 1, "last_name": "Doe"} Let's rename name key to first_name:
let { name: first_name, ...rest } = obj; obj = { first_name, ...rest } Now the Object is:
{"first_name": "John", "id": 1, "last_name": "Doe"} If you want to keep the same order of the object
changeObjectKeyName(objectToChange, oldKeyName: string, newKeyName: string){ const otherKeys = cloneDeep(objectToChange); delete otherKeys[oldKeyName]; const changedKey = objectToChange[oldKeyName]; return {...{[newKeyName] : changedKey} , ...otherKeys}; } How to use:
changeObjectKeyName ( {'a' : 1}, 'a', 'A'); 1After searching for many answers, this is the best solution for me:
const renameKey = (oldKey, newKey) => { _.reduce(obj, (newObj, value, key) => { newObj[oldKey === key ? newKey : key] = value return newObj }, {}) } Instead of replacing the original key, it constructs a new object, it's clear. The way in the question worked but will change order of the object, because it adds the new key-value to the last.
