JavaScript: Object Rename Key

456,280

Solution 1

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.

Solution 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];

Solution 3

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;
        }
    }
);

Solution 4

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

Solution 5

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'}
Share:
456,280
Jean Vincent
Author by

Jean Vincent

Currently developing ReactiveSets/toubkal, a High-Performances Reactive Web Application Framework under nodejs providing best performances in terms of latency, raw-speed and code size. Toubkal also allows higher code productivity thanks to an concise intuitive API. Check it out on github.

Updated on July 08, 2022

Comments

  • Jean Vincent
    Jean Vincent almost 2 years

    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 ];
    
  • Ivo Wetzel
    Ivo Wetzel over 13 years
    @ChaosPandion sorry about that, but I'm really tired of bug ridden JS code, I'm currently writing a Guide (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)
  • ChaosPandion
    ChaosPandion over 13 years
    @Ivo - Could you explain why you feel extending the prototype is bad? Prototypes were made for extending baby!
  • Ivo Wetzel
    Ivo Wetzel over 13 years
    @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.
  • ChaosPandion
    ChaosPandion over 13 years
    @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.
  • David Tang
    David Tang over 13 years
    @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?
  • Jean Vincent
    Jean Vincent over 13 years
    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
    Jean Vincent over 13 years
    @Box9, it should be standard practice but it is not, especially among "standard" developers.
  • Jean Vincent
    Jean Vincent over 11 years
    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.
  • Bent Cardan
    Bent Cardan almost 11 years
    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.
  • Scott Stafford
    Scott Stafford almost 10 years
    In case it matters, I believe this particular usage of ES5 is an IE9-and-newer solution.
  • Brandon Minton
    Brandon Minton almost 10 years
    This code works but the caveat is that if the new key name already exists, its value is going to get down trodden: jsfiddle.net/ryurage/B7x8x
  • Dex
    Dex about 9 years
    @BrandonMinton I came across this too. I've added a simple fix with readability in mind.
  • David Dias
    David Dias almost 9 years
    Made an updated version of your solution that doesn't transform static keys to 'undefined' here: 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?
  • BlondinkaBrain
    BlondinkaBrain over 8 years
    ooops! var object = {b : '123', 'c' : 'bbb'}; var str = JSON.stringify(object); str = str.replace(/b/g, 'newKey'); str = str.replace(/c/g, 'newKey2'); object = JSON.parse(str);
  • mix3d
    mix3d over 8 years
    How does this compare for speed?
  • mix3d
    mix3d over 8 years
    Also runs into a potential issue of somewhere in the datavalues is the same string as the old key name.
  • Jed Fox
    Jed Fox over 7 years
    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 How to Answer. source
  • Tudor Morar
    Tudor Morar over 7 years
    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..
  • rsp
    rsp about 7 years
    "Works perfectly" for certain definitions of "perfectly". Try to rename 'a' in { a: 1, aa: 2, aaa: 3} or try to rename an object with values that are anything more than strings or numbers or booleans, or try with circular references.
  • ikhsan
    ikhsan almost 7 years
    if the object contains function or date object, this will not work
  • Akin Hwan
    Akin Hwan over 6 years
    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
  • mjarraya
    mjarraya about 6 years
    This truly is a horrendous solution
  • jose
    jose about 6 years
    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])
  • Tim
    Tim over 5 years
    Try: delete Object.assign(o, {newKey: o.oldKey }).oldKey; Worked well for me
  • Jon Adams
    Jon Adams over 5 years
    Perhaps you could explain what this is doing and how it works?
  • Soumya Kanti
    Soumya Kanti over 5 years
    Why is there the square brace [] around newKey? The solution works without that actually.
  • Soumya Kanti
    Soumya Kanti over 5 years
    Ok - I got my answer. It's the ES6 feature. For anyone else stumbled on this like me, here is a good answer.
  • lowcrawler
    lowcrawler about 5 years
    This answer would be stronger if your variable names were more verbose.
  • lowcrawler
    lowcrawler almost 5 years
    Perhaps? Sorry, I forget what I was thinking with my initial comment.
  • TomoMiha
    TomoMiha over 4 years
    This solution worked for me, but pay attention to always return a 'key' variable. Example: if(key === 'oldKey') { return 'newKey'; } return key;
  • blueprintchris
    blueprintchris over 4 years
    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
  • TAHA SULTAN TEMURI
    TAHA SULTAN TEMURI over 4 years
    this is the best solution
  • franco phong
    franco phong about 4 years
    This is the best solution. But need some understand about spread operator.
  • user3808307
    user3808307 about 4 years
    @JeffLowery what if it was an array of objects? Do I have to do a foreach or can I do with spread too?
  • Jeff Lowery
    Jeff Lowery about 4 years
    @user3808307 You can do a spread on an array, and objects in the array.
  • Johann
    Johann about 4 years
    NOTE: The use of Object.assign only does a shallow copy.
  • gignu
    gignu over 3 years
    Thx a lot, I was getting confused by all the other answers. This one is simple and maintains the order. Exactly what I was looking for!
  • desh
    desh over 3 years
    i cant seem to understand this part const { [OLD_KEY]: replaceByKey, ...rest } = obj
  • homerThinking
    homerThinking over 3 years
    works fine for rename the key, but the value is lost
  • Dexygen
    Dexygen over 3 years
    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.
  • Devin Rhode
    Devin Rhode over 3 years
    Absolutely brilliant. Using the first parameter, oldProp, for some magical destructing in the 3rd param.
  • Krishna
    Krishna over 3 years
    read about destructuring of object. here
  • steviesh
    steviesh over 3 years
    This only copies the enumerable properties - if you're looking for identical behavior I do not believe this will work.
  • Dror Bar
    Dror Bar almost 3 years
    Why use Object.assign instead of using spread operator (...)?
  • Andre Goulart
    Andre Goulart almost 3 years
    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])
  • Ruan Mendes
    Ruan Mendes over 2 years
    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.
  • Admin
    Admin over 2 years
    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.
  • L.Dutch
    L.Dutch over 2 years
    This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review
  • aderchox
    aderchox over 2 years
    It first creates the new key, then merges it into the object, then deletes the old key from the merged object. Nice solution.
  • ya_dimon
    ya_dimon about 2 years
    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 :)
  • Raqha
    Raqha about 2 years
    Nice, this suites my use case perfeclty
  • Valeriu Paloş
    Valeriu Paloş about 2 years
    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).
  • user3342816
    user3342816 about 2 years
    @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..