JavaScript: Objektumbenennungsschlüssel

299

Gibt es eine clevere (dh optimierte) Möglichkeit, einen Schlüssel in einem Javascript-Objekt umzubenennen?

Ein nicht optimierter Weg wäre:

o[ new_key ] = o[ old_key ];
delete o[ old_key ];
Jean Vincent
quelle
14
Was meinst du mit "optimiert"? Ich glaube nicht, dass es knapper werden kann. Es gibt keine eingebaute Operation zum Umbenennen.
Pointy
9
Das ist alles was du bekommen kannst. Ich würde mich um andere Dinge in meiner Bewerbung kümmern. Übrigens haben Sie es mit Objekten zu tun, nicht mit Arrays. In JavaScript gibt es keine assoziativen Arrays (im engeren Sinne).
Felix Kling
3
@ Jean Vincent: Ist es so langsam?
Felix Kling
8
Dies ist die optimierteste und grundlegendste Version
Livingston Samuel
4
Ihre Version ist die schnellste in allen modernen Browsern außer Safari, Beispiel Testfall @ jsperf.com/livi-006
Livingston Samuel

Antworten:

193

Ich glaube, der vollständigste (und korrekteste) Weg, dies zu tun, wäre:

if (old_key !== new_key) {
    Object.defineProperty(o, new_key,
        Object.getOwnPropertyDescriptor(o, old_key));
    delete o[old_key];
}

Diese Methode stellt sicher, dass sich die umbenannte Eigenschaft identisch mit der ursprünglichen verhält .

Außerdem scheint mir die Möglichkeit, dies in eine Funktion / Methode zu packen und Object.prototypeeinzufügen, für Ihre Frage irrelevant zu sein.

Valeriu Paloş
quelle
1
Dies ist eine schöne ES5-Lösung mit dem echten Plus, alle Eigenschaften zu erhalten. Dies ist also nicht "optimiert", aber auf ES5 definitiv genauer.
Jean Vincent
6
mit einiger Skepsis gegenüber dem Schreiben von Dingen mit Unterstrichen bewertet, aber das lag natürlich an der Person, die die Frage stellte. Dies ist aus meiner Sicht die richtige Antwort.
Bent Cardan
3
Für den Fall, dass es wichtig ist, glaube ich, dass diese spezielle Verwendung von ES5 eine IE9-und neuere Lösung ist.
Scott Stafford
1
Ich schlage vor, eine Validierung hinzuzufügen, dass o.old_key existiert. Ändern: if (old_key !== new_key)zu: if (old_key !== new_key && o[old_key])
Jose
100

Sie können die Arbeit in eine Funktion einbinden und sie dem ObjectPrototyp zuweisen . Verwenden Sie möglicherweise den fließenden Schnittstellenstil, um mehrere Umbenennungen durchzuführen.

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-spezifisch

Ich wünschte, die Syntax wäre nicht so komplex, aber es ist auf jeden Fall schön, mehr Kontrolle zu haben.

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;
        }
    }
);
ChaosPandion
quelle
4
@ChaosPandion Entschuldigung, aber ich habe den fehlerhaften JS-Code wirklich satt. Ich schreibe derzeit einen Leitfaden ( github.com/BonsaiDen/JavaScript-Garden ) über alle Macken (einschließlich der, die Sie jetzt behoben haben). Dies könnte mich in eine Art Rant-Modus versetzt haben;) (Entfernte jetzt die -1)
Ivo Wetzel
1
@Ivo - Können Sie erklären, warum Sie die Erweiterung des Prototyps für schlecht halten? Prototypen wurden für die Verlängerung des Babys gemacht!
ChaosPandion
5
@Ivo - Ich stimme zu, dass es riskant ist, aber nichts hindert mich daran, den Prototyp zu erweitern, wenn ich der Meinung bin, dass dies zu einem ausdrucksstärkeren Code führt. Obwohl ich aus einer ECMAScript 5-Denkweise komme, in der Sie eine Eigenschaft als nicht aufzählbar markieren können Object.defineProperty.
ChaosPandion
3
@Ivo - Wenn es üblich ist, immer hasOwnPropertynach Eigenschaften und innerhalb von for ... inSchleifen zu suchen , warum ist es dann wichtig, wenn wir Object erweitern?
David Tang
2
Dieser Code funktioniert, aber die Einschränkung ist, dass wenn der neue Schlüsselname bereits existiert, sein Wert getreten wird: jsfiddle.net/ryurage/B7x8x
Brandon Minton
83

Wenn Sie Ihr Quellobjekt mutieren, kann ES6 dies in einer Zeile tun.

delete Object.assign(o, {[newKey]: o[oldKey] })[oldKey];

Oder zwei Zeilen, wenn Sie ein neues Objekt erstellen möchten.

const newObject = {};
delete Object.assign(newObject, o, {[newKey]: o[oldKey] })[oldKey];
nverba
quelle
5
Versuchen Sie: object.assign löschen (o, {newKey: o.oldKey}). OldKey; Hat gut für mich
Tim
2
Warum gibt es die quadratische Klammer []um newKey? Die Lösung funktioniert eigentlich ohne das.
Soumya Kanti
2
Ok - ich habe meine Antwort bekommen. Es ist die ES6-Funktion. Für alle anderen, die wie ich darauf gestoßen sind, ist hier eine gute Antwort .
Soumya Kanti
1
Diese Antwort wäre stärker, wenn Ihre Variablennamen ausführlicher wären.
Lowcrawler
1
Vielleicht? Entschuldigung, ich habe vergessen, was ich mit meinem ersten Kommentar gedacht habe.
Lowcrawler
42

Falls jemand eine Liste von Eigenschaften umbenennen muss:

function renameKeys(obj, newKeys) {
  const keyValues = Object.keys(obj).map(key => {
    const newKey = newKeys[key] || key;
    return { [newKey]: obj[key] };
  });
  return Object.assign({}, ...keyValues);
}

Verwendungszweck:

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
quelle
2
Diese Antwort sollte akzeptiert werden und hat für meinen Anwendungsfall hervorragend funktioniert. Ich musste eine API-Antwort konvertieren, der Ländernamen eine unnötige Zeichenfolge voranstellte. Verwandelte das Objekt in ein Array von Schlüsseln und ordnete jeden Schlüssel mit der Teilstring-Methode zu und gab ein neues Objekt mit neuem Schlüssel und Wert zurück, das durch den ursprünglichen Schlüssel indiziert wurde
Akin Hwan
1
Dies ist schön, da der alte Schlüssel nicht gelöscht wird. Durch Löschen des alten Schlüssels wird der Schlüssel vollständig aus dem Objekt entfernt, wenn sich der Schlüsselname nicht geändert hat. In meinem Beispiel wurde die Umwandlung ich my_object_propertyzu myObjectProperty, aber wenn mein Eigentum Einzel formuliert ist, dann wurde der Schlüssel entfernt. +1
blueprintchris
25

Ich möchte nur den ES6(ES2015)Weg benutzen !

Wir müssen mit der Zeit gehen!

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-Bildschirmverknüpfung

xgqfrms-gildata
quelle
1
Fand dieses als sauberere Lösung, wenn Sie ein fehlerhaftes Objekt in ein brandneues umstrukturiertes Objekt umwandeln möchten.
NJInamdar
5
Gut, aber ich denke, const {k1: kA, k2: kB, k3: kC,} = old_obj ist ausreichend? Keine Notwendigkeit zu verbreiten (es sei denn, Sie möchten eine Kopie von old_obj).
Hans
@ Hans, ja du hast recht. Aber in dieser Situation möchte ich einige Schlüssel umbenennen, also sollte ich sie verbreiten.
xgqfrms-gildata
2
Dies erfordert viel mehr Code, ist weniger effizient und erstellt ein neues Objekt. Das Umbenennen einer Eigenschaft impliziert das Mutieren des Objekts. Neu ist nicht immer besser.
Jean Vincent
16

Wenn Sie Ihre Daten nicht mutieren möchten, ziehen Sie diese Funktion in Betracht ...

renameProp = (oldProp, newProp, {[oldProp]:old, ...others}) => ({
    [newProp]: old,
    ...others
})

Eine gründliche Erklärung von Yazeed Bzadough https://medium.com/front-end-hacking/immutably-rename-object-keys-in-javascript-5f6353c7b6dd


Mulhoon
quelle
Dies ist die beste Lösung. Aber brauchen etwas Verständnis über Spread Operator.
Franco Phong
13

Die meisten Antworten hier halten die Reihenfolge der Schlüssel-Wert-Paare von JS-Objekten nicht aufrecht. Wenn Sie beispielsweise eine Form von Objektschlüssel-Wert-Paaren auf dem Bildschirm haben, die Sie ändern möchten, ist es wichtig, die Reihenfolge der Objekteinträge beizubehalten.

Die ES6-Methode zum Durchlaufen des JS-Objekts und zum Ersetzen des Schlüssel-Wert-Paares durch das neue Paar durch einen geänderten Schlüsselnamen lautet wie folgt:

let newWordsObject = {};

Object.keys(oldObject).forEach(key => {
  if (key === oldKey) {
    let newPair = { [newKey]: oldObject[oldKey] };
    newWordsObject = { ...newWordsObject, ...newPair }
  } else {
    newWordsObject = { ...newWordsObject, [key]: oldObject[key] }
  }
});

Die Lösung behält die Reihenfolge der Einträge bei, indem der neue Eintrag anstelle des alten hinzugefügt wird.

afalak
quelle
Perfekt, das ist was ich brauchte
p0358
12

Sie können lodash versuchen _.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
quelle
Diese Lösung hat bei mir funktioniert, aber achten Sie darauf, immer eine 'Schlüssel'-Variable zurückzugeben. Beispiel: if (key === 'oldKey') {return 'newKey'; } Eingabetaste;
TomoMiha
12

Eine Variation unter Verwendung des Objektzerstörungs- und Spread-Operators:

    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};
Jeff Lowery
quelle
Vielleicht könnten Sie erklären, was dies tut und wie es funktioniert?
Jon Adams
@ JeffLowery Was wäre, wenn es ein Array von Objekten wäre? Muss ich einen Foreach machen oder kann ich auch mit Spread machen?
user3808307
@ user3808307 Sie können eine Verteilung auf ein Array und Objekte im Array durchführen.
Jeff Lowery
7

Persönlich der effektivste Weg, Schlüssel im Objekt umzubenennen, ohne extra schwere Plugins und Räder zu implementieren:

var str = JSON.stringify(object);
str = str.replace(/oldKey/g, 'newKey');
str = str.replace(/oldKey2/g, 'newKey2');

object = JSON.parse(str);

Sie können es auch einschließen, try-catchwenn Ihr Objekt eine ungültige Struktur hat. Funktioniert perfekt :)

Novitoll
quelle
12
ooops! var object = {b: '123', 'c': 'bbb'}; var str = JSON.stringify (Objekt); str = str.replace (/ b / g, 'newKey'); str = str.replace (/ c / g, 'newKey2'); object = JSON.parse (str);
BlondinkaBrain
4
Wie ist das für die Geschwindigkeit zu vergleichen?
mix3d
16
Außerdem tritt ein potenzielles Problem auf, bei dem irgendwo in den Datenwerten dieselbe Zeichenfolge wie der alte Schlüsselname vorhanden ist.
mix3d
4
"Funktioniert perfekt" für bestimmte Definitionen von "perfekt". Versuchen Sie , umbenennen 'a'in { a: 1, aa: 2, aaa: 3}oder versuchen , ein Objekt mit Werten zu benennen , die nichts mehr sind als Strings oder Zahlen oder Boolesche Werte, oder versuchen , mit zirkulären Referenzen.
rsp
1
Wenn das Objekt ein Funktions- oder
Datumsobjekt
7

So fügen Sie jedem Schlüssel ein Präfix hinzu:

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
quelle
5

Ich würde so etwas machen:

function renameKeys(dict, keyMap) {
  return _.reduce(dict, function(newDict, val, oldKey) {
    var newKey = keyMap[oldKey] || oldKey
    newDict[newKey] = val 
    return newDict
  }, {})
}
tldr
quelle
3
Hier wurde eine aktualisierte Version Ihrer Lösung erstellt, die statische Schlüssel nicht in "undefiniert" umwandelt : gist.github.com/diasdavid/f8997fb0bdf4dc1c3543 Trotzdem wird das Problem, Schlüssel auf mehreren Ebenen des JSON neu zuordnen zu wollen, nicht behoben Objekt (verschachtelte Schlüssel neu zuordnen), Ideen?
David Dias
4

Ich würde sagen, dass es aus konzeptioneller Sicht besser wäre, das alte Objekt (das des Webdienstes) so zu belassen, wie es ist, und die benötigten Werte in ein neues Objekt einzufügen. Ich gehe davon aus, dass Sie sowieso an der einen oder anderen Stelle bestimmte Felder extrahieren, wenn nicht auf dem Client, dann zumindest auf dem Server. Die Tatsache, dass Sie Feldnamen verwendet haben, die mit denen des Webdienstes identisch sind, nur in Kleinbuchstaben, ändert daran nichts. Also würde ich raten, so etwas zu tun:

var myObj = {
    field1: theirObj.FIELD1, 
    field2: theirObj.FIELD2,
    (etc)
}

Natürlich mache ich hier alle möglichen Annahmen, die möglicherweise nicht zutreffen. Wenn dies nicht auf Sie zutrifft oder wenn es zu langsam ist (oder? Ich habe es nicht getestet, aber ich stelle mir vor, dass der Unterschied mit zunehmender Anzahl von Feldern kleiner wird), ignorieren Sie dies alles :)

Wenn Sie dies nicht möchten und nur bestimmte Browser unterstützen müssen, können Sie mit den neuen Gettern auch "Großbuchstaben (Feld)" zurückgeben: siehe http://robertnyman.com/2009/05/28 / getters-and-setters-with-javascript-code-samples-and-demos / und die Links auf dieser Seite für weitere Informationen.

BEARBEITEN:

Unglaublich, das ist auch fast doppelt so schnell, zumindest auf meinem FF3.5 bei der Arbeit. Siehe: http://jsperf.com/spiny001

Stacheliger Norman
quelle
Vielen Dank für Ihre Bemühungen, aber der Anwendungsfall manipuliert keine statischen Objekte, da deren Struktur und Tiefe unbekannt ist. Wenn möglich, möchte ich mich an den ursprünglichen Umfang der Frage halten.
Jean Vincent
4

Dies bietet zwar keine bessere Lösung für das Umbenennen eines Schlüssels, bietet jedoch eine schnelle und einfache ES6-Möglichkeit, alle Schlüssel in einem Objekt umzubenennen, ohne die darin enthaltenen Daten zu mutieren.

let b = {a: ["1"], b:["2"]};
Object.keys(b).map(id => {
  b[`root_${id}`] = [...b[id]];
  delete b[id];
});
console.log(b);
Tudor Morar
quelle
3
Bitte verwenden Sie den Bearbeitungslink, um zu erklären, wie dieser Code funktioniert, und geben Sie nicht nur den Code an, da eine Erklärung zukünftigen Lesern eher hilft. Siehe auch Antworten . Quelle
Jed Fox
Genau. Die Frage wird nicht speziell beantwortet, aber es hat mir geholfen, die Aufgabe als Lösung für das Umbenennen aller Schlüssel im Objekt zu erledigen. Vielleicht habe ich das Thema verpasst ..
Tudor Morar
3

Einige der auf dieser Seite aufgeführten Lösungen haben einige Nebenwirkungen:

  1. Beeinflussen Sie die Position des Schlüssels im Objekt und fügen Sie ihn unten hinzu (falls dies für Sie von Bedeutung ist).
  2. würde in IE9 + nicht funktionieren (wieder, wenn dies für Sie wichtig ist)

Hier ist eine Lösung, die die Position des Schlüssels an derselben Stelle beibehält und in IE9 + kompatibel ist, jedoch ein neues Objekt erstellen muss und möglicherweise nicht die schnellste Lösung ist:

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

Bitte beachten Sie: IE9 unterstützt möglicherweise nicht jeden im strengen Modus

Jasdeep Khalsa
quelle
2

Hier ist ein Beispiel zum Erstellen eines neuen Objekts mit umbenannten Schlüsseln.

let x = { id: "checkout", name: "git checkout", description: "checkout repository" };

let renamed = Object.entries(x).reduce((u, [n, v]) => {
  u[`__${n}`] = v;
  return u;
}, {});
张 焱 伟
quelle
2

Ein weiterer Weg mit der leistungsstärksten REDUCE- Methode.

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

SubbU
quelle
1

Dies ist eine kleine Modifikation, die ich an der Funktion von Pomber vorgenommen habe. Um ein Array von Objekten anstelle eines Objekts allein nehmen zu können, können Sie auch den Index aktivieren. Auch die "Schlüssel" können von einem Array zugewiesen werden

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

Prüfung

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);
Jasp402
quelle
1

Ihr Weg ist meiner Meinung nach optimiert. Aber Sie werden mit neu geordneten Schlüsseln enden. Der neu erstellte Schlüssel wird am Ende angehängt. Ich weiß, dass Sie sich niemals auf die Schlüsselreihenfolge verlassen sollten, aber wenn Sie diese beibehalten müssen, müssen Sie alle Schlüssel durchgehen und nacheinander neue Objekte erstellen und dabei den betreffenden Schlüssel ersetzen.

So was:

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.
quelle
0
  • Sie können ein Dienstprogramm verwenden, um dies zu handhaben.
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
quelle
0

Probieren Sie es einfach in Ihrem Lieblingseditor <3 aus

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
quelle