Existe uma maneira inteligente (ou seja, otimizada) de renomear uma chave em um objeto javascript?
Uma maneira não otimizada seria:
o[ new_key ] = o[ old_key ];
delete o[ old_key ];
Existe uma maneira inteligente (ou seja, otimizada) de renomear uma chave em um objeto javascript?
Uma maneira não otimizada seria:
o[ new_key ] = o[ old_key ];
delete o[ old_key ];
Respostas:
A maneira mais completa (e correta) de fazer isso seria, acredito:
if (old_key !== new_key) {
Object.defineProperty(o, new_key,
Object.getOwnPropertyDescriptor(o, old_key));
delete o[old_key];
}
Este método garante que a propriedade renomeada se comporte de forma idêntica à original.
Além disso, parece-me que a possibilidade de agrupar isso em uma função / método e colocá-lo Object.prototype
é irrelevante em relação à sua pergunta.
if (old_key !== new_key)
para: if (old_key !== new_key && o[old_key])
Você pode agrupar o trabalho em uma função e atribuí-lo ao Object
protótipo. Talvez use o estilo de interface fluente para fazer com que várias renomeações fluam.
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;
};
Específico do ECMAScript 5
Eu gostaria que a sintaxe não fosse tão complexa, mas é definitivamente bom ter mais controle.
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
para verificar propriedades e dentro de for ... in
loops, por que importa se estendemos o Object?
Se você estiver modificando seu objeto de origem, o ES6 poderá fazê-lo em uma linha.
delete Object.assign(o, {[newKey]: o[oldKey] })[oldKey];
Ou duas linhas, se você deseja criar um novo objeto.
const newObject = {};
delete Object.assign(newObject, o, {[newKey]: o[oldKey] })[oldKey];
[]
em torno de newKey
? A solução funciona sem isso, na verdade.
Caso alguém precise renomear uma lista de propriedades:
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
para myObjectProperty
, no entanto, se minha propriedade tivesse uma palavra, a chave foi removida. 1
ES6(ES2015)
caminho!precisamos acompanhar os tempos!
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 você não deseja alterar seus dados, considere esta função ...
renameProp = (oldProp, newProp, {[oldProp]:old, ...others}) => ({
[newProp]: old,
...others
})
Uma explicação completa de Yazeed Bzadough https://medium.com/front-end-hacking/immutably-rename-object-keys-in-javascript-5f6353c7b6dd
A maioria das respostas aqui falham em manter a ordem dos pares de valores-chave do JS Object. Se você possui uma forma de pares de valores-chave de objeto na tela que deseja modificar, por exemplo, é importante preservar a ordem das entradas do objeto.
A maneira do ES6 de percorrer o objeto JS e substituir o par de valores-chave pelo novo par por um nome de chave modificado seria algo como:
let newWordsObject = {};
Object.keys(oldObject).forEach(key => {
if (key === oldKey) {
let newPair = { [newKey]: oldObject[oldKey] };
newWordsObject = { ...newWordsObject, ...newPair }
} else {
newWordsObject = { ...newWordsObject, [key]: oldObject[key] }
}
});
A solução preserva a ordem das entradas adicionando a nova entrada no lugar da antiga.
Você pode tentar 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>
Uma variação usando o operador de desestruturação e propagação de objetos:
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};
Pessoalmente, a maneira mais eficaz de renomear chaves no objeto sem implementar plugins e rodas extra pesados:
var str = JSON.stringify(object);
str = str.replace(/oldKey/g, 'newKey');
str = str.replace(/oldKey2/g, 'newKey2');
object = JSON.parse(str);
Você também pode envolvê-lo try-catch
se seu objeto tiver uma estrutura inválida. Funciona perfeitamente :)
'a'
em { a: 1, aa: 2, aaa: 3}
ou tentar mudar o nome de um objeto com valores que são nada mais do que cordas ou números ou booleans, ou tentar com referências circulares.
Eu faria algo assim:
function renameKeys(dict, keyMap) {
return _.reduce(dict, function(newDict, val, oldKey) {
var newKey = keyMap[oldKey] || oldKey
newDict[newKey] = val
return newDict
}, {})
}
Eu diria que seria melhor, do ponto de vista conceitual, deixar o objeto antigo (o do serviço da web) como está e colocar os valores necessários em um novo objeto. Suponho que você esteja extraindo campos específicos em um ponto ou outro de qualquer maneira, se não no cliente, pelo menos no servidor. O fato de você optar por usar nomes de campos iguais aos do serviço da Web, apenas em minúsculas, não altera isso. Então, eu aconselho a fazer algo assim:
var myObj = {
field1: theirObj.FIELD1,
field2: theirObj.FIELD2,
(etc)
}
Claro, estou fazendo todos os tipos de suposições aqui, o que pode não ser verdade. Se isso não se aplicar a você, ou se for muito lento (não é? Não testei, mas imagino que a diferença diminua à medida que o número de campos aumenta), ignore tudo isso :)
Se você não quiser fazer isso e precisar suportar apenas navegadores específicos, também poderá usar os novos getters para também retornar "maiúsculas (campo)": consulte http://robertnyman.com/2009/05/28 / getters-and-setters-with-javascript-code-samples-and-demos / e os links nessa página para obter mais informações.
EDITAR:
Incrivelmente, isso também é quase duas vezes mais rápido, pelo menos no meu FF3.5 no trabalho. Veja: http://jsperf.com/spiny001
Embora isso não forneça exatamente uma solução melhor para renomear uma chave, ele fornece uma maneira rápida e fácil do ES6 de renomear todas as chaves em um objeto sem alterar os dados que eles contêm.
let b = {a: ["1"], b:["2"]};
Object.keys(b).map(id => {
b[`root_${id}`] = [...b[id]];
delete b[id];
});
console.log(b);
Algumas das soluções listadas nesta página têm alguns efeitos colaterais:
Aqui está uma solução que mantém a posição da chave no mesmo local e é compatível no IE9 +, mas precisa criar um novo objeto e pode não ser a solução mais rápida:
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;
}
Observe: O IE9 pode não suportar forEach no modo estrito
Mais uma maneira com o mais poderoso método REDUCE .
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);
Essa é uma pequena modificação que fiz na função de pomber; Para poder pegar uma matriz de objetos em vez de um objeto sozinho e você também pode ativar o índice. também as "Teclas" podem ser atribuídas por uma matriz
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;
}
teste
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);
Seu caminho é otimizado, na minha opinião. Mas você terminará com chaves reordenadas. A chave recém-criada será anexada no final. Eu sei que você nunca deve confiar na ordem das chaves, mas se precisar preservá-las, precisará passar por todas as chaves e construir um novo objeto, um por um, substituindo a chave em questão durante esse processo.
Como isso:
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' };