Czy istnieje sprytny (tj. Zoptymalizowany) sposób zmiany nazwy klucza w obiekcie javascript?
Niezoptymalizowanym sposobem byłoby:
o[ new_key ] = o[ old_key ];
delete o[ old_key ];
Czy istnieje sprytny (tj. Zoptymalizowany) sposób zmiany nazwy klucza w obiekcie javascript?
Niezoptymalizowanym sposobem byłoby:
o[ new_key ] = o[ old_key ];
delete o[ old_key ];
Odpowiedzi:
Uważam, że najbardziej kompletnym (i poprawnym) sposobem na zrobienie tego jest:
if (old_key !== new_key) {
Object.defineProperty(o, new_key,
Object.getOwnPropertyDescriptor(o, old_key));
delete o[old_key];
}
Ta metoda zapewnia zachowanie właściwości o zmienionej nazwie w stosunku do właściwości oryginalnej.
Wydaje mi się również, że możliwość zawinięcia tego w funkcję / metodę i wstawienia go Object.prototype
jest nieistotna z punktu widzenia twojego pytania.
if (old_key !== new_key)
na: if (old_key !== new_key && o[old_key])
Możesz zawinąć pracę w funkcję i przypisać ją do Object
prototypu. Być może użyj płynnego stylu interfejsu, aby umożliwić przepływ wielu nazw.
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 Specyficzny
Chciałbym, żeby składnia nie była tak skomplikowana, ale zdecydowanie miło jest mieć większą kontrolę.
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
sprawdzanie właściwości i for ... in
pętli, to dlaczego ma to znaczenie, jeśli rozszerzamy Object?
Jeśli mutujesz obiekt źródłowy, ES6 może to zrobić w jednej linii.
delete Object.assign(o, {[newKey]: o[oldKey] })[oldKey];
Lub dwie linie, jeśli chcesz utworzyć nowy obiekt.
const newObject = {};
delete Object.assign(newObject, o, {[newKey]: o[oldKey] })[oldKey];
[]
wokół jest kwadratowa klamra newKey
? Rozwiązanie działa bez tego.
W przypadku, gdy ktoś musi zmienić nazwę listy właściwości:
function renameKeys(obj, newKeys) {
const keyValues = Object.keys(obj).map(key => {
const newKey = newKeys[key] || key;
return { [newKey]: obj[key] };
});
return Object.assign({}, ...keyValues);
}
Stosowanie:
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
na myObjectProperty
, ale jeśli moja właściwość była jednosłowa, klucz został usunięty. +1
ES6(ES2015)
drogi!musimy nadążać za duchem czasu!
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"}
Jeśli nie chcesz mutować danych, rozważ tę funkcję ...
renameProp = (oldProp, newProp, {[oldProp]:old, ...others}) => ({
[newProp]: old,
...others
})
Dokładne wyjaśnienie Yazeed Bzadough https://medium.com/front-end-hacking/immutably-rename-object-keys-in-javascript-5f6353c7b6dd
Większość odpowiedzi tutaj nie utrzymuje porządku par klucz-wartość obiektu JS. Jeśli masz na ekranie formę par klucz-wartość obiektu, którą chcesz zmodyfikować, ważne jest na przykład zachowanie kolejności wpisów obiektów.
Sposób zapętlania obiektu JS przez ES6 i zamiany pary klucz-wartość na nową parę ze zmodyfikowaną nazwą klucza wyglądałby mniej więcej tak:
let newWordsObject = {};
Object.keys(oldObject).forEach(key => {
if (key === oldKey) {
let newPair = { [newKey]: oldObject[oldKey] };
newWordsObject = { ...newWordsObject, ...newPair }
} else {
newWordsObject = { ...newWordsObject, [key]: oldObject[key] }
}
});
Rozwiązanie zachowuje kolejność wpisów, dodając nowy wpis w miejsce starego.
Możesz spróbować 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>
Odmiana wykorzystująca funkcję destrukcji obiektów i operatora rozprzestrzeniania
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};
Osobiście najskuteczniejszy sposób zmiany nazwy kluczy w obiekcie bez implementacji dodatkowych ciężkich wtyczek i kół:
var str = JSON.stringify(object);
str = str.replace(/oldKey/g, 'newKey');
str = str.replace(/oldKey2/g, 'newKey2');
object = JSON.parse(str);
Możesz go również owinąć, try-catch
jeśli Twój obiekt ma niepoprawną strukturę. Działa świetnie :)
'a'
w { a: 1, aa: 2, aaa: 3}
lub spróbuj zmienić nazwę obiektu z wartościami, które są niczym więcej niż ciągami, liczbami lub wartościami logicznymi, albo spróbuj z odwołaniami cyklicznymi.
Zrobiłbym coś takiego:
function renameKeys(dict, keyMap) {
return _.reduce(dict, function(newDict, val, oldKey) {
var newKey = keyMap[oldKey] || oldKey
newDict[newKey] = val
return newDict
}, {})
}
Powiedziałbym, że z koncepcyjnego punktu widzenia lepiej byłoby po prostu zostawić stary obiekt (ten z serwisu internetowego) w obecnej postaci i umieścić potrzebne wartości w nowym obiekcie. Zakładam, że i tak wyodrębniasz określone pola w tym czy innym miejscu, jeśli nie na kliencie, to przynajmniej na serwerze. Fakt, że zdecydowałeś się używać nazw pól, które są takie same jak te z serwisu internetowego, tylko małe litery, tak naprawdę tego nie zmienia. Radziłbym więc zrobić coś takiego:
var myObj = {
field1: theirObj.FIELD1,
field2: theirObj.FIELD2,
(etc)
}
Oczywiście przyjmuję tutaj różne założenia, co może nie być prawdą. Jeśli to Cię nie dotyczy lub jest zbyt wolne (prawda? Nie testowałem, ale wyobrażam sobie, że różnica maleje wraz ze wzrostem liczby pól), zignoruj to wszystko :)
Jeśli nie chcesz tego robić i musisz obsługiwać tylko określone przeglądarki, możesz również użyć nowych programów pobierających, aby zwrócić również „wielkie litery (pola)”: patrz http://robertnyman.com/2009/05/28 / getters-and-setters-with-javascript-code-samples-and-demos / oraz linki na tej stronie, aby uzyskać więcej informacji.
EDYTOWAĆ:
Niesamowicie, jest to prawie dwa razy szybsze, przynajmniej na moim FF3.5 w pracy. Zobacz: http://jsperf.com/spiny001
Chociaż nie daje to lepszego rozwiązania w kwestii zmiany nazwy klucza, zapewnia on szybki i łatwy sposób zmiany nazwy wszystkich kluczy w obiekcie przy jednoczesnym braku mutacji zawartych w nich danych.
let b = {a: ["1"], b:["2"]};
Object.keys(b).map(id => {
b[`root_${id}`] = [...b[id]];
delete b[id];
});
console.log(b);
Niektóre rozwiązania wymienione na tej stronie mają pewne skutki uboczne:
Oto rozwiązanie, które utrzymuje pozycję klucza w tym samym miejscu i jest kompatybilne z IE9 +, ale musi utworzyć nowy obiekt i może nie być najszybszym rozwiązaniem:
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;
}
Uwaga: IE9 może nie obsługiwać każdego w trybie ścisłym
Jeszcze inny sposób z najbardziej wydajną metodą REDUKCJI .
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);
To jest mała modyfikacja, którą wprowadziłem do funkcji pomber; Aby móc wziąć tablicę obiektów zamiast samego obiektu, a także można aktywować indeks. także „Klucze” mogą być przypisywane przez tablicę
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);
Twoja droga jest zoptymalizowana, moim zdaniem. Ale skończysz z uporządkowanymi kluczami. Nowo utworzony klucz zostanie dołączony na końcu. Wiem, że nigdy nie powinieneś polegać na kolejności kluczy, ale jeśli musisz ją zachować, będziesz musiał przejść przez wszystkie klucze i zbudować nowy obiekt jeden po drugim, zastępując dany klucz podczas tego procesu.
Lubię to:
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' };