478

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 ];
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Jean Vincent
  • 11,995
  • 7
  • 32
  • 24
  • 21
    What do you mean by "optimized"? I don't think it can get any more terse than that; there's no "rename" built-in operation. – Pointy Jan 10 '11 at 14:30
  • 12
    That is all you can get. I would worry about other things in my application. And btw, you are dealing with objects, not arrays. There are no associative arrays in JavaScript (in a strict sense). – Felix Kling Jan 10 '11 at 14:32
  • Optimized would be either faster or more compact, or more readable. – Jean Vincent Jan 10 '11 at 14:32
  • 5
    @Jean Vincent: Is it that slow? – Felix Kling Jan 10 '11 at 14:32
  • 12
    this is the most optimized and basic version – Livingston Samuel Jan 10 '11 at 14:34
  • @Felix, not very slow, but at least ugly, and could potentially become a problem once we use worker threads. – Jean Vincent Jan 10 '11 at 14:38
  • 6
    your version is the fastest in all modern browsers except safari, sample test case @ http://jsperf.com/livi-006 – Livingston Samuel Jan 10 '11 at 14:42
  • 1
    I'm very curious as to why you would want to do this. As @Felix already said, it's an object so you can't really 'rename keys', because they're object properties. So, if you want to rename keys on a regular basis, maybe you should use a different type of data structure? What are you using it for? – Spiny Norman Jan 10 '11 at 14:59
  • 1
    Worker threads work on the principle of message passing (passing and returning a JSON string); they don't do shared memory, if that is your concern. If you are looking for a less "ugly" solution consider putting it in a function like @hunter suggests or extend the Array object by adding a rename method to it's prototype. – nedk Jan 10 '11 at 15:00
  • 1
    @Spiny Norman, I use a web service that returns JSON with ALL_CAPS object keys. I'd like to rename these keys. – Jean Vincent Jan 10 '11 at 23:48
  • Changed "array" to "object" as rightly suggested by several commenters. – Jean Vincent Jan 11 '11 at 00:00
  • @Jean Vincent Ah, I see. In that case, I think it might be better (and, as it turns out, faster) to just create a new object that represents what you want to do with the data after you retrieved it from the web service. See also my answer below :) – Spiny Norman Jan 11 '11 at 08:41
  • 1
    if you use node.js you could try https://www.npmjs.com/package/rename-keys – jonschlinkert Nov 12 '15 at 04:45
  • @jonschlinkert - this looks great, but it seems it iterates over, and makes changes to, all keys? To target one specific key, I suppose you could do: `if (key === "_x") { return "x"; } else { return key; }` – user1063287 Sep 15 '18 at 07:23
  • JavaScript: combining the speed of a scripting language with the cumbersomeness of a compiled language since 1995 :) – webb May 07 '21 at 16:05
  • Can someone explain the problem to me? Start to think I learned something incorrect; if object o[ old_key ] is an object there will be two references to the same object. And that should be harmless as JS by nature is single threaded. if o[ old_key ] is primitive value (number/string etc.) i could be a problem if you using both names in your code, but I think that is more of a theoretical problem. And creating new references and copy primitive values should be very fast. Some overhead for GC for primitive values, but should be negletible. Or should I try to relearn something? – Griffin Aug 17 '21 at 09:23
  • 1
    @Griffin no, your knowledge is correct. much less expensive copying a pointer and trashing the old one... – zergski Jul 09 '23 at 06:57

36 Answers36

255

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.

Myrddin Emrys
  • 42,126
  • 11
  • 38
  • 51
Valeriu Paloş
  • 3,459
  • 1
  • 20
  • 12
  • 1
    This is a nice ES5-only solution with the real plus of preserving all properties. So this is not "optimized" but definitly more accurate on ES5. – Jean Vincent Feb 06 '13 at 15:28
  • 10
    upvoted with some skepticism toward writing_things_with_underscores, but of course that was due to the person asking the question. this is the correct response in my view. – Bent Cardan Jul 06 '13 at 01:38
  • 3
    In case it matters, I believe this particular usage of ES5 is an IE9-and-newer solution. – Scott Stafford Jul 22 '14 at 14:14
  • 3
    I suggest adding a validation that o.old_key exists. Changing: `if (old_key !== new_key)` to: `if (old_key !== new_key && o[old_key])` – jose Jun 15 '18 at 11:37
  • I also suggest adding a validation that `o.new_key` already exists, for avoid overwriting. Changing: `if (old_key !== new_key && o[old_key])` to `if (old_key !== new_key && o[old_key] && !o[new_key])` – Andre Goulart Aug 13 '21 at 02:07
  • Normally I would agree with you, but in this case I think it's clear enough, otherwise nobody would have understood the question (which uses `o`). – Valeriu Paloş Jun 01 '22 at 11:44
  • @BentCardan Hah. I always use underscores. One thing is that it clearly distinguish multi-word properties from native JS i.e. `foo.get_key()` and in general I find it easier to read which is the ultimate goal anyhow.. – user3342816 Jun 04 '22 at 04:39
  • @ValeriuPaloş, how to keep the sequence of object keys ? this method puts new key at the end of object.... – Jamshaid Tariq Oct 12 '22 at 06:02
  • @JamshaidTariq Although in practice the order of object keys is (reasonably) well preserved in modern JS runtimes, the JS specification does not guarantee it, so it's considered bad practice to rely on this order. Change your code to use arrays if you really need key ordering, since arrays do guarantee order and you can actually insert elements at specific positions to enforce this. – Valeriu Paloş Oct 13 '22 at 07:22
185

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];
nverba
  • 3,803
  • 2
  • 18
  • 21
111

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;
        }
    }
);
Brian Ogden
  • 18,439
  • 10
  • 97
  • 176
ChaosPandion
  • 77,506
  • 18
  • 119
  • 157
  • 4
    @ChaosPandion sorry about that, but I'm really tired of bug ridden JS code, I'm currently writing a Guide (https://github.com/BonsaiDen/JavaScript-Garden) about all the quirks (including the one you now have fixed), this might have put me into some kind of rant mode ;) (Removed the -1 now) – Ivo Wetzel Jan 10 '11 at 15:58
  • 1
    @Ivo - Could you explain why you feel extending the prototype is bad? Prototypes were made for extending baby! – ChaosPandion Jan 10 '11 at 15:58
  • 1
    @ChaosPandion Not the **natives** one, because they introduce all the mess with `in` etc. Prototype.js is a great example **why** it is bad, even its developers have admitted that is was a bad thing to use it for the library. – Ivo Wetzel Jan 10 '11 at 16:00
  • 5
    @Ivo - I agree that it is risky, but there is nothing that will stop me from extending the prototype if I felt it lead to more expressive code. Although I am coming from an ECMAScript 5 mindset where you can mark a property as non-enumerable via `Object.defineProperty`. – ChaosPandion Jan 10 '11 at 16:02
  • 3
    @Ivo - If it is proper practice to always use `hasOwnProperty` to check for properties and within `for ... in` loops, then why does it matter if we extend Object? – David Tang Jan 11 '11 at 00:08
  • @Box9, it should be standard practice but it is not, especially among "standard" developers. – Jean Vincent Jan 12 '11 at 08:43
  • 2
    This code works but the caveat is that if the new key name already exists, its value is going to get down trodden: http://jsfiddle.net/ryurage/B7x8x/ – Brandon Minton Jul 22 '14 at 16:06
  • @BrandonMinton I came across this too. I've added a simple fix with readability in mind. – Dex May 21 '15 at 07:48
  • Nobody modifies built-in prototypes in 2021. Main reason is not just that it shows up in `for in` loops but because a method could be introduced in the future and this would clash with it. Just make a `function renameProps(obj, oldName, newName){}` so you never have to worry. – Ruan Mendes Dec 16 '21 at 15:26
  • don't extend proto, only extend your collection... do classes, otherwise this is the best answer here – zergski Jul 08 '23 at 11:27
87

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"}
pomber
  • 23,132
  • 10
  • 81
  • 94
  • 2
    this should be accepted answer, worked great for my use case. I had to convert an API response that was prefixing Country Names with unnecessary string. Turned Object into array of keys and mapped through each key with substring method and returned a new object with new key and value indexed by original key – Akin Hwan Feb 10 '18 at 18:46
  • 1
    This is nice as it doesn't delete the old key. Deleting the old key will remove the key entirely from the object if the key name hasn't changed. In my example, I was converting `my_object_property` to `myObjectProperty`, however, if my property was single-worded, then the key was removed. +1 – blueprintchris Dec 05 '19 at 14:49
44

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'}
piotr_cz
  • 8,755
  • 2
  • 30
  • 25
  • 6
    This is by far the simplest in my opinion and should be the accepted answer. I used it to lower-case all my keys and substitute spaces with underscores. – Dexygen Oct 28 '20 at 16:15
  • This is the only one reserving the keys order. – PeiSong Nov 13 '22 at 03:16
34

I 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"}

demo screen shortcut

  • 1
    Found this one as cleaner solution when you want to transform a malformed object to a brand new restructured one. – Nagama Inamdar Feb 15 '18 at 12:27
  • 7
    Good one, but I think const {k1: kA, k2: kB, k3: kC,} = old_obj is sufficient? no need to spread (unless you want a copy of old_obj). – Björn Feb 24 '18 at 15:30
  • @Hans, yeah you are right. But in this situation, I want to rename some keys, so I should to spread them. –  Jun 20 '18 at 01:21
  • 2
    This requires much more code, will be less efficient, and creates a new object. Renaming a property implies mutating the object. Newer is not always better. – Jean Vincent Oct 11 '18 at 12:58
33

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 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}
Devin Rhode
  • 23,026
  • 8
  • 58
  • 72
Jeff Lowery
  • 2,492
  • 2
  • 32
  • 40
32

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


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

Devin Rhode
  • 23,026
  • 8
  • 58
  • 72
Mulhoon
  • 1,852
  • 21
  • 26
  • This is the best solution. But need some understand about spread operator. – franco phong Apr 28 '20 at 11:46
  • Absolutely brilliant. Using the first parameter, `oldProp`, for some magical destructing in the 3rd param. – Devin Rhode Nov 24 '20 at 03:46
  • The `ts` example does not help, an example, [further down](https://stackoverflow.com/a/69552710/1705829) is missing. [See my comment](https://stackoverflow.com/questions/4647817/javascript-object-rename-key/69552710#comment131614290_69552710) – Timo Nov 24 '22 at 12:14
26

Most 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.

afalak
  • 481
  • 5
  • 9
19

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>
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
  • This solution worked for me, but pay attention to always return a 'key' variable. Example: if(key === 'oldKey') { return 'newKey'; } return key; – TomoMiha Oct 02 '19 at 09:37
13

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

Aayush Bhattacharya
  • 1,628
  • 18
  • 17
12

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 :)

Novitoll
  • 820
  • 1
  • 9
  • 22
11

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);
// { "firstkey": "value1", "secondkey": "value2", "thirdkey": "value3"}
SubbU
  • 349
  • 3
  • 6
7

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
  }, {})
}
tldr
  • 11,924
  • 15
  • 75
  • 120
  • 3
    Made an updated version of your solution that doesn't transform static keys to 'undefined' here: https://gist.github.com/diasdavid/f8997fb0bdf4dc1c3543 Nevertheless, it still doesn't over the problem of wanting to remap keys at several levels of the JSON object (remaping nested keys), ideas? – David Dias Sep 04 '15 at 01:53
7

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
}
Pablo
  • 586
  • 5
  • 14
  • 1
    i cant seem to understand this part const { [OLD_KEY]: replaceByKey, ...rest } = obj – desh Oct 02 '20 at 04:37
  • 1
    read about destructuring of object. [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) – Krishna Dec 03 '20 at 14:31
5

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);
Tudor Morar
  • 3,720
  • 2
  • 27
  • 25
  • 4
    Please use the [edit] link to explain how this code works and don't just give the code, as an explanation is more likely to help future readers. See also [answer]. [source](http://stackoverflow.com/users/5244995) – Jed Fox Jan 27 '17 at 16:45
  • I agree. It does not answer the question specifically but it helped me in getting the job done as a solution for renaming all keys in the object. Maybe I missed the topic.. – Tudor Morar Jan 30 '17 at 12:40
5

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

Spiny Norman
  • 8,277
  • 1
  • 30
  • 55
  • Thank you very much for your efforts but the use case does not manipulate static objects as their structure and depth is unkown. So if possible I would like to stick to the original scope of the question. – Jean Vincent Jan 12 '11 at 08:38
  • now account for all that gc that has to be done as you're creating carbage every .. single .. time and you'll see that this is the least performant mo.. also change a value of first level property and see if it will sync with any reference you had to the old one somewhere else :) – zergski Jul 08 '23 at 11:33
5

If 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
}
eli
  • 51
  • 1
  • 2
5

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"}
Umang
  • 212
  • 5
  • 18
4

Some of the solutions listed on this page have some side-effects:

  1. affect the position of the key in the object, adding it to the bottom (if this matters to you)
  2. 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

Jasdeep Khalsa
  • 6,740
  • 8
  • 38
  • 58
2

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;
}, {});
张焱伟
  • 61
  • 7
1

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);
brass monkey
  • 5,841
  • 10
  • 36
  • 61
Jasp402
  • 402
  • 3
  • 12
1

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;
Tomas M
  • 6,919
  • 6
  • 27
  • 33
1
  • 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' };

Muhammed Moussa
  • 4,589
  • 33
  • 27
1

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});
Xavier Lambros
  • 776
  • 11
  • 19
  • I got a working example: `var arr = { id: 'toto_id', name: 'toto', age: 35 };var arr2 = renameKeys({ id: 'value', name: 'label' }, arr);console.log(arr2)`. How do you elaborate it to use an `array of objects` instead of a single object? – Timo Nov 24 '22 at 12:11
1

I'd like to do this

const originalObj = {
  a: 1,
  b: 2,
  c: 3, // need replace this 'c' key into 'd'
};

const { c, ...rest } = originalObj;

const newObj = { ...rest, d: c };

console.log({ originalObj, newObj });
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 29 '21 at 07:15
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/30694098) – L.Dutch Dec 31 '21 at 07:02
1

In case someone needs to rename a key of object:

 
  const renameKeyObject = (obj, oldKey, newKey) => {
      if (oldKey === newKey) return obj;
      Object.keys(obj).forEach((key) => {
          if (key === oldKey) {
              obj[newKey] = obj[key];
              delete obj[key];
            } else if (obj[key] !== null && typeof obj[key] === "object") {
                obj[key] = renameKeyObject(obj[key], oldKey, newKey);
              }
            });
  return obj;
};
1

c'mon in 2023 we should know better!

Sooo many answers completely neglect memory & retaining reference.. the former is where you actually 'optimize' you code.

The spread operator into an anon obj not only decouples the reference from the rest of your project, it also creates garbage the size of your object. Seeing jitters and stutters in your pixel perfect parralax animation? well, thats the gc cleaning that up for you.. 'Object.assign' would solve the reference thing, only it doesn't copy all props while also iterating over the whole thing..

back to basics people!

reassign -> delete is the most optimal, as you're only allocating a new pointer, while also deleting the old one

and if you really need a oneliner just parenwrap..

delete (o[new_key] = o[old_key], o)[old_key]

though the two liner is much more readable..

and don't rely on insertion order of a hashmap. use arrays with pointers for 'smaller' lists or linked list for larger ones

zergski
  • 793
  • 3
  • 10
  • 1
    Thanks, I think this is the most useful answer in a very long time. I did not know that delete would reclaim the memory immediately, not relying and waiting on the garbage collector. This makes it effectively more optimized which was the stated goal of the question. – Jean Vincent Jul 08 '23 at 18:06
  • 1
    I fail to see how this answer is different from the top answers. – starball Jul 08 '23 at 19:26
  • it's not, but the explanation is – zergski Jul 09 '23 at 05:52
  • @JeanVincent happy to oblige! ..might sound extremely pointer-outery, but might be good info for some.. the memory is marked as deleted, as is standard with any memory, free to be overwritten but effectively ignored by gc .. more often than not it'll remain allocated to your app. seems to vary dep on where the buffer lives, heap or stack, bit unsure here.. the guys at v8 did a ton of magic and I've yet to understand some of their spells – zergski Jul 09 '23 at 06:53
  • I've done some research, unfortunately was not able to find information about delete enabling to bypass GC. Could you point me to a source that shows this ? Thanks – Jean Vincent Jul 09 '23 at 09:50
0

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);
Subrata Sarkar
  • 111
  • 2
  • 3
0
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 };
Bensu Rachel
  • 184
  • 1
  • 5
0

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,
} */
  • spread into anon new object.. allocates memory.. means the old one now is unused and has to be gc'd, also it decouples the reference so if you update the new, if you have aywhere you used the old. it will not be updated.. – zergski Jul 08 '23 at 10:58
0

After 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.

Renny Ren
  • 77
  • 1
  • 4
-1
const data = res
const lista = []
let newElement: any

if (data && data.length > 0) {

  data.forEach(element => {
      newElement = element

      Object.entries(newElement).map(([key, value]) =>
        Object.assign(newElement, {
          [key.toLowerCase()]: value
        }, delete newElement[key], delete newElement['_id'])
      )
    lista.push(newElement)
  })
}
return lista
HK boy
  • 1,398
  • 11
  • 17
  • 25
-1

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');
Yoav Schniederman
  • 5,253
  • 3
  • 28
  • 32
  • `const changedKey` should be `const valueOfChangedKey`. And does not work, if the key is in the middle of object. + You need the cloneDeep function. So not that good solution :) – ya_dimon Apr 13 '22 at 12:04
-1

Generally, if u want to get a new object (without mutating the original one) with keys renamed according a keyMap - you can use the following implementation based on lodash mapKeys:

const {mapKeys} = require('lodash');
const renameKeys = (obj, keyMap) => _.mapKeys(obj, (value, key) => keyMap[key] || key);

Usage example:

renameKeys({a: 1, b: 2, c: 3}, {c: 'p', a: 'm'})
> {m: 1, b: 2, p: 3}
Alexander
  • 7,484
  • 4
  • 51
  • 65
-2
function iterate(instance) {
  for (let child of instance.tree_down) iterate(child);

  instance.children = instance.tree_down;
  delete instance.tree_down;
}

iterate(link_hierarchy);

console.log(link_hierarchy);
Rio Weber
  • 2,757
  • 1
  • 20
  • 28
  • [A code-only answer is not high quality](//meta.stackoverflow.com/questions/392712/explaining-entirely-code-based-answers). While this code may be useful, you can improve it by saying why it works, how it works, when it should be used, and what its limitations are. Please [edit] your answer to include explanation and link to relevant documentation. – Stephen Ostermiller Apr 27 '22 at 09:27