JavaScript: объект переименовать ключ
Есть ли умный (то есть оптимизированный) способ переименовать ключ в объекте JavaScript?
Неоптимизированный способ будет:
o[ new_key ] = o[ old_key ];
delete o[ old_key ];
37 ответов
Я полагаю, что наиболее полный (и правильный) способ сделать это:
if (old_key !== new_key) {
Object.defineProperty(o, new_key,
Object.getOwnPropertyDescriptor(o, old_key));
delete o[old_key];
}
Этот метод гарантирует, что переименованное свойство ведет себя идентично исходному.
Кроме того, мне кажется, что возможность обернуть это в функцию / метод и поместить его в Object.prototype
не имеет отношения к вашему вопросу.
Если вы изменяете исходный объект, ES6 может сделать это в одну строку.
delete Object.assign(o, {[newKey]: o[oldKey] })[oldKey];
Или две строки, если вы хотите создать новый объект.
const newObject = {};
delete Object.assign(newObject, o, {[newKey]: o[oldKey] })[oldKey];
Вы можете обернуть работу в функцию и назначить ее Object
прототип. Возможно, используйте свободный стиль интерфейса, чтобы сделать несколько переименований потоком.
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 специфический
Хотелось бы, чтобы синтаксис не был таким сложным, но было бы неплохо иметь больше контроля.
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;
}
}
);
В случае, если кому-то нужно переименовать список свойств:
function renameKeys(obj, newKeys) {
const keyValues = Object.keys(obj).map(key => {
const newKey = newKeys[key] || key;
return { [newKey]: obj[key] };
});
return Object.assign({}, ...keyValues);
}
Использование:
const obj = { a: "1", b: "2" };
const newKeys = { a: "A", c: "C" };
const renamedObj = renameKeys(obj, newKeys);
console.log(renamedObj);
// {A:"1", b:"2"}
Чтобы добавить префикс к каждому ключу:
const obj = {foo: 'bar'}
const altObj = Object.fromEntries(
Object.entries(obj).map(([key, value]) =>
// Modify key here
[`x-${key}`, value]
)
)
// altObj = {'x-foo': 'bar'}
Я хотел бы просто использовать ES6(ES2015)
путь!
нам нужно идти в ногу со временем!
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"}
Вариант с использованием объекта деструктуризации и оператора распространения:
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 shorthand properties **kA, kB, kC**;
// spread the remaining properties in the **rest** variable
const newObj = {kA, kB, kC, ...rest};
Если вы не хотите изменять свои данные, рассмотрите эту функцию...
renameProp = (oldProp, newProp, {[oldProp]:old, ...others}) => ({
[newProp]: old,
...others
})
Полное объяснение Язида Бзадоу https://medium.com/front-end-hacking/immutably-rename-object-keys-in-javascript-5f6353c7b6dd
Большинство ответов здесь не поддерживают порядок пар ключ-значение JS Object. Например, если на экране имеется форма пар ключ-значение объекта, которую вы хотите изменить, важно сохранить порядок записей объектов.
Способ ES6 циклически проходить по объекту JS и заменять пару ключ-значение новой парой с измененным именем ключа будет выглядеть примерно так:
let newWordsObject = {};
Object.keys(oldObject).forEach(key => {
if (key === oldKey) {
let newPair = { [newKey]: oldObject[oldKey] };
newWordsObject = { ...newWordsObject, ...newPair }
} else {
newWordsObject = { ...newWordsObject, [key]: oldObject[key] }
}
});
Решение сохраняет порядок записей, добавляя новую запись вместо старой.
Вы можете попробовать Лодаш _.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>
Переименуйте ключ, но избегайте изменения исходных параметров объектов
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"}]
лучше иметь новый массив
Лично, наиболее эффективный способ переименования ключей в объекте без реализации дополнительных тяжелых плагинов и колес:
var str = JSON.stringify(object);
str = str.replace(/oldKey/g, 'newKey');
str = str.replace(/oldKey2/g, 'newKey2');
object = JSON.parse(str);
Вы также можете обернуть его в try-catch
если ваш объект имеет недопустимую структуру. Работает отлично:)
Еще один способ с самым мощным методом 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);
Я бы сделал что-то вроде этого:
function renameKeys(dict, keyMap) {
return _.reduce(dict, function(newDict, val, oldKey) {
var newKey = keyMap[oldKey] || oldKey
newDict[newKey] = val
return newDict
}, {})
}
Просто попробуйте в своем любимом редакторе <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
}
Другой способ переименовать ключ объекта:
Рассмотрим этот объект:
let obj = {"name": "John", "id": 1, "last_name": "Doe"}
Давайте переименуем ключ name в first_name:
let { name: first_name, ...rest } = obj;
obj = { first_name, ...rest }
Теперь Объект:
{"first_name": "John", "id": 1, "last_name": "Doe"}
Я бы сказал, что было бы лучше с концептуальной точки зрения просто оставить старый объект (объект из веб-службы) как есть и поместить нужные значения в новый объект. Я предполагаю, что вы в любом случае извлекаете определенные поля в той или иной точке, если не на клиенте, то, по крайней мере, на сервере. Тот факт, что вы решили использовать имена полей, которые совпадают с именами из веб-службы, только в нижнем регистре, на самом деле не меняет этого. Итак, я бы посоветовал сделать что-то вроде этого:
var myObj = {
field1: theirObj.FIELD1,
field2: theirObj.FIELD2,
(etc)
}
Конечно, я делаю здесь всевозможные предположения, которые могут быть неверными. Если это не относится к вам, или если это слишком медленно (не так ли? Я не проверял, но я думаю, что разница уменьшается по мере увеличения количества полей), пожалуйста, игнорируйте все это:)
Если вы не хотите этого делать, и вам нужно только поддерживать определенные браузеры, вы также можете использовать новые методы получения, чтобы также возвращать "верхний регистр (поле)": см. http://robertnyman.com/2009/05/28/getters-and-setters-with-javascript-code-samples-and-demos/ и ссылки на этой странице для получения дополнительной информации.
РЕДАКТИРОВАТЬ:
Невероятно, но это также почти вдвое быстрее, по крайней мере, на моем FF3.5 на работе. Смотрите: http://jsperf.com/spiny001
Если вы хотите сохранить порядок итераций (порядок вставки), вот предложение:
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
}
Хотя это не совсем лучшее решение для переименования ключа, оно обеспечивает быстрый и простой способ ES6 переименовать все ключи в объекте, не изменяя данные, которые они содержат.
let b = {a: ["1"], b:["2"]};
Object.keys(b).map(id => {
b[`root_${id}`] = [...b[id]];
delete b[id];
});
console.log(b);
Некоторые из решений, перечисленных на этой странице, имеют некоторые побочные эффекты:
- влияет на положение ключа в объекте, добавляя его внизу (если это важно для вас)
- не будет работать в IE9+ (опять же, если это важно для вас)
Вот решение, которое сохраняет положение ключа в том же месте и совместимо с IE9+, но должно создавать новый объект и, возможно, не является самым быстрым решением:
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;
}
Обратите внимание: IE9 может не поддерживать forEach в строгом режиме
Вот пример для создания нового объекта с переименованными ключами.
let x = { id: "checkout", name: "git checkout", description: "checkout repository" };
let renamed = Object.entries(x).reduce((u, [n, v]) => {
u[`__${n}`] = v;
return u;
}, {});
Ваш путь оптимизирован, на мой взгляд. Но у вас получатся переупорядоченные ключи. Вновь созданный ключ будет добавлен в конце. Я знаю, что вы никогда не должны полагаться на порядок ключей, но если вам нужно сохранить его, вам нужно будет пройти через все ключи и создать новый объект один за другим, заменяя соответствующий ключ во время этого процесса.
Как это:
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;
давай, в 2023 году мы должны знать лучше!
Ооочень много ответов полностью игнорируют память и сохраняют ссылку. В первом вы фактически «оптимизируете» свой код.
Оператор распространения в anon obj не только отделяет ссылку от остальной части вашего проекта, но и создает мусор размером с ваш объект. Видите дрожание и заикание в идеальной пиксельной анимации паралакса? ну, это сборщик мусора, который очищает это за вас. «Object.assign» решит проблему со ссылкой, только он не копирует все реквизиты, а также перебирает все это..
вернемся к основам, люди!
переназначение -> удаление является наиболее оптимальным, поскольку вы выделяете только новый указатель, а также удаляете старый
и если вам действительно нужен однострочник, просто оберните скобками..
delete (o[new_key] = o[old_key], o)[old_key]
хотя двухстрочный вариант гораздо читабельнее..
и не полагайтесь на порядок вставки хэш-карты. используйте массивы с указателями для «меньших» списков или связанный список для больших.
Мой способ адаптировать хороший пост @Mulhoon typescript для изменения нескольких ключей:
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});
Это небольшая модификация, которую я сделал для функции pomber; Чтобы иметь возможность взять массив объектов вместо одного объекта, а также вы можете активировать индекс. также "Ключи" могут быть назначены массивом
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;
}
тестовое задание
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);
- Вы можете использовать утилиту, чтобы справиться с этим.
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' };
var myObject = { oldKey: "value" };
myObject = JSON.parse(JSON.stringify(myObject).replace("oldKey", "newKey"));
я бы хотел сделать это
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 });
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 };