Esiste un modo intelligente (ovvero ottimizzato) per rinominare una chiave in un oggetto JavaScript?
Un modo non ottimizzato sarebbe:
o[ new_key ] = o[ old_key ];
delete o[ old_key ];
Esiste un modo intelligente (ovvero ottimizzato) per rinominare una chiave in un oggetto JavaScript?
Un modo non ottimizzato sarebbe:
o[ new_key ] = o[ old_key ];
delete o[ old_key ];
Risposte:
Il modo più completo (e corretto) per farlo sarebbe, credo:
if (old_key !== new_key) {
Object.defineProperty(o, new_key,
Object.getOwnPropertyDescriptor(o, old_key));
delete o[old_key];
}
Questo metodo garantisce che la proprietà rinominata si comporti in modo identico a quella originale.
Inoltre, mi sembra che la possibilità di avvolgerlo in una funzione / metodo e metterlo in questione Object.prototype
sia irrilevante per quanto riguarda la tua domanda.
if (old_key !== new_key)
a: if (old_key !== new_key && o[old_key])
È possibile avvolgere il lavoro in una funzione e assegnarlo al Object
prototipo. Forse usa lo stile dell'interfaccia fluente per far fluire più rinominazioni.
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 Specifico
Vorrei che la sintassi non fosse così complessa, ma è sicuramente bello avere più controllo.
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;
}
}
);
Object.defineProperty
.
hasOwnProperty
per verificare la presenza di proprietà e all'interno dei for ... in
loop, perché importa se estendiamo Object?
Se stai mutando il tuo oggetto sorgente, ES6 può farlo in una riga.
delete Object.assign(o, {[newKey]: o[oldKey] })[oldKey];
O due righe se si desidera creare un nuovo oggetto.
const newObject = {};
delete Object.assign(newObject, o, {[newKey]: o[oldKey] })[oldKey];
[]
intorno newKey
? La soluzione funziona senza questo in realtà.
Nel caso in cui qualcuno debba rinominare un elenco di proprietà:
function renameKeys(obj, newKeys) {
const keyValues = Object.keys(obj).map(key => {
const newKey = newKeys[key] || key;
return { [newKey]: obj[key] };
});
return Object.assign({}, ...keyValues);
}
Uso:
const obj = { a: "1", b: "2" };
const newKeys = { a: "A", c: "C" };
const renamedObj = renameKeys(obj, newKeys);
console.log(renamedObj);
// {A:"1", b:"2"}
my_object_property
in myObjectProperty
, tuttavia, se la mia proprietà era a una sola parola, la chiave è stata rimossa. +1
ES6(ES2015)
strada!dobbiamo stare al passo con i tempi!
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"}
Se non vuoi mutare i tuoi dati, considera questa funzione ...
renameProp = (oldProp, newProp, {[oldProp]:old, ...others}) => ({
[newProp]: old,
...others
})
Una spiegazione approfondita di Yazeed Bzadough https://medium.com/front-end-hacking/immutably-rename-object-keys-in-javascript-5f6353c7b6dd
La maggior parte delle risposte non riesce a mantenere l'ordine delle coppie chiave-valore di JS Object. Se sullo schermo è presente una forma di coppie chiave-valore oggetto che si desidera modificare, ad esempio, è importante preservare l'ordine delle voci dell'oggetto.
Il modo ES6 di eseguire il looping dell'oggetto JS e di sostituire la coppia chiave-valore con la nuova coppia con un nome chiave modificato sarebbe simile a:
let newWordsObject = {};
Object.keys(oldObject).forEach(key => {
if (key === oldKey) {
let newPair = { [newKey]: oldObject[oldKey] };
newWordsObject = { ...newWordsObject, ...newPair }
} else {
newWordsObject = { ...newWordsObject, [key]: oldObject[key] }
}
});
La soluzione mantiene l'ordine delle voci aggiungendo la nuova voce al posto di quella precedente.
Puoi provare 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>
Una variante che utilizza l'operatore di distruzione e diffusione dell'oggetto:
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};
Personalmente, il modo più efficace per rinominare le chiavi nell'oggetto senza implementare plugin e ruote extra pesanti:
var str = JSON.stringify(object);
str = str.replace(/oldKey/g, 'newKey');
str = str.replace(/oldKey2/g, 'newKey2');
object = JSON.parse(str);
Puoi anche avvolgerlo try-catch
se il tuo oggetto ha una struttura non valida. Funziona perfettamente :)
'a'
in { a: 1, aa: 2, aaa: 3}
o provare per rinominare un oggetto con valori che sono qualcosa di più di stringhe o numeri o booleani, o provare con riferimenti circolari.
Farei qualcosa del genere:
function renameKeys(dict, keyMap) {
return _.reduce(dict, function(newDict, val, oldKey) {
var newKey = keyMap[oldKey] || oldKey
newDict[newKey] = val
return newDict
}, {})
}
Direi che sarebbe meglio da un punto di vista concettuale lasciare semplicemente il vecchio oggetto (quello del servizio web) così com'è e inserire i valori necessari in un nuovo oggetto. Presumo che tu stia estraendo campi specifici in un punto o nell'altro comunque, se non sul client, almeno sul server. Il fatto che tu abbia scelto di utilizzare nomi di campo uguali a quelli del servizio Web, solo in minuscolo, non cambia questo. Quindi, consiglierei di fare qualcosa del genere:
var myObj = {
field1: theirObj.FIELD1,
field2: theirObj.FIELD2,
(etc)
}
Certo, sto facendo tutti i tipi di ipotesi qui, il che potrebbe non essere vero. Se questo non si applica a te, o se è troppo lento (vero? Non ho ancora testato, ma immagino che la differenza diminuisca all'aumentare del numero di campi), per favore ignora tutto questo :)
Se non vuoi farlo e devi solo supportare browser specifici, puoi anche usare i nuovi getter per restituire anche "maiuscolo (campo)": vedi http://robertnyman.com/2009/05/28 / getters-and-setters-with-javascript-code-samples-and-demos / e i collegamenti su quella pagina per ulteriori informazioni.
MODIFICARE:
Incredibilmente, anche questo è quasi il doppio più veloce, almeno sulla mia FF3.5 al lavoro. Vedi: http://jsperf.com/spiny001
Sebbene ciò non fornisca esattamente una soluzione migliore per rinominare una chiave, fornisce un modo ES6 rapido e semplice per rinominare tutte le chiavi in un oggetto senza mutare i dati che contengono.
let b = {a: ["1"], b:["2"]};
Object.keys(b).map(id => {
b[`root_${id}`] = [...b[id]];
delete b[id];
});
console.log(b);
Alcune delle soluzioni elencate in questa pagina hanno alcuni effetti collaterali:
Ecco una soluzione che mantiene la posizione della chiave nello stesso posto ed è compatibile in IE9 +, ma deve creare un nuovo oggetto e potrebbe non essere la soluzione più veloce:
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;
}
Nota: IE9 potrebbe non supportare Ognuno in modalità rigorosa
Ancora un altro modo con il metodo REDUCE più potente .
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);
Questa è una piccola modifica che ho apportato alla funzione di pomber; Per essere in grado di prendere una matrice di oggetti anziché un solo oggetto e puoi anche attivare l'indice. anche i "tasti" possono essere assegnati da un 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);
La tua strada è ottimizzata, secondo me. Ma finirai con le chiavi riordinate. La chiave appena creata verrà aggiunta alla fine. So che non dovresti mai fare affidamento sull'ordine delle chiavi, ma se devi preservarlo, dovrai esaminare tutte le chiavi e costruire un nuovo oggetto uno per uno, sostituendo la chiave in questione durante quel processo.
Come questo:
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;
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' };