มีวิธีฉลาด (เช่นปรับให้เหมาะสม) เพื่อเปลี่ยนชื่อคีย์ในวัตถุจาวาสคริปต์หรือไม่?
วิธีที่ไม่เหมาะสมจะเป็น:
o[ new_key ] = o[ old_key ];
delete o[ old_key ];
มีวิธีฉลาด (เช่นปรับให้เหมาะสม) เพื่อเปลี่ยนชื่อคีย์ในวัตถุจาวาสคริปต์หรือไม่?
วิธีที่ไม่เหมาะสมจะเป็น:
o[ new_key ] = o[ old_key ];
delete o[ old_key ];
คำตอบ:
วิธีที่สมบูรณ์แบบที่สุด (และถูกต้อง) ในการทำเช่นนี้คือฉันเชื่อว่า:
if (old_key !== new_key) {
Object.defineProperty(o, new_key,
Object.getOwnPropertyDescriptor(o, old_key));
delete o[old_key];
}
วิธีนี้ทำให้มั่นใจได้ว่าคุณสมบัติที่ถูกเปลี่ยนชื่อนั้นจะทำงานเหมือนกันกับคุณสมบัติดั้งเดิม
นอกจากนี้ดูเหมือนว่าสำหรับฉันแล้วความเป็นไปได้ที่จะห่อสิ่งนี้ไว้ในฟังก์ชั่น / วิธีการและการนำไปใช้Object.prototype
นั้นไม่เกี่ยวข้องกับคำถามของคุณ
if (old_key !== new_key)
เป็น: if (old_key !== new_key && o[old_key])
คุณสามารถห่องานในฟังก์ชั่นและกำหนดให้กับ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;
}
}
);
Object.defineProperty
ความคิดที่คุณสามารถทำเครื่องหมายทรัพย์สินที่ไม่นับผ่าน
hasOwnProperty
เพื่อตรวจสอบคุณสมบัติและภายในfor ... in
ลูปเสมอดังนั้นทำไมจึงมีความสำคัญหากเราขยาย Object?
หากคุณกำลังกลายพันธุ์วัตถุต้นทางของคุณ ES6 สามารถทำได้ในหนึ่งบรรทัด
delete Object.assign(o, {[newKey]: o[oldKey] })[oldKey];
หรือสองบรรทัดถ้าคุณต้องการสร้างวัตถุใหม่
const newObject = {};
delete Object.assign(newObject, o, {[newKey]: o[oldKey] })[oldKey];
[]
รอบอยู่newKey
? วิธีการแก้ปัญหาใช้งานได้จริง
ในกรณีที่มีคนต้องการเปลี่ยนชื่อรายการคุณสมบัติ:
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"}
my_object_property
เป็นmyObjectProperty
อย่างไรก็ตามถ้าคุณสมบัติของฉันเป็นคำเดียวแล้วคีย์ถูกลบ +1
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"}
หากคุณไม่ต้องการที่จะกลายพันธุ์ข้อมูลของคุณให้พิจารณาฟังก์ชั่นนี้ ...
renameProp = (oldProp, newProp, {[oldProp]:old, ...others}) => ({
[newProp]: old,
...others
})
คำอธิบายอย่างละเอียดโดย Yazeed Bzadough 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
lodash
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>
การเปลี่ยนแปลงโดยใช้การทำลายวัตถุและตัวดำเนินการแพร่กระจาย:
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};
โดยส่วนตัวแล้ววิธีที่มีประสิทธิภาพที่สุดในการเปลี่ยนชื่อคีย์ในวัตถุโดยไม่ต้องใช้ปลั๊กอินและล้อเสริมขนาดใหญ่เป็นพิเศษ:
var str = JSON.stringify(object);
str = str.replace(/oldKey/g, 'newKey');
str = str.replace(/oldKey2/g, 'newKey2');
object = JSON.parse(str);
นอกจากนี้คุณยังสามารถรวมไว้ในtry-catch
วัตถุของคุณถ้ามีโครงสร้างที่ไม่ถูกต้อง ทำงานได้อย่างสมบูรณ์แบบ :)
'a'
ใน{ a: 1, aa: 2, aaa: 3}
หรือพยายามที่จะเปลี่ยนชื่อวัตถุที่มีค่าอะไรมากไปกว่าสตริงหรือตัวเลขหรือบูลีนหรือลองกับการอ้างอิงแบบวงกลม
ในการเพิ่มคำนำหน้าให้กับแต่ละคีย์:
const obj = {foo: 'bar'}
const altObj = Object.fromEntries(
Object.entries(obj).map(([key, value]) =>
// Modify key here
[`x-${key}`, value]
)
)
// altObj = {'x-foo': 'bar'}
ฉันจะทำสิ่งนี้:
function renameKeys(dict, keyMap) {
return _.reduce(dict, function(newDict, val, oldKey) {
var newKey = keyMap[oldKey] || oldKey
newDict[newKey] = val
return newDict
}, {})
}
ฉันจะบอกว่ามันจะดีกว่าจากมุมมองแนวคิดที่จะเพียงแค่ทิ้งวัตถุเก่า (หนึ่งจากบริการเว็บ) ตามที่มันเป็นและใส่ค่าที่คุณต้องการในวัตถุใหม่ ฉันสมมติว่าคุณกำลังแยกเขตข้อมูลเฉพาะที่จุดหนึ่งหรืออื่น ๆ ต่อไปถ้าไม่ได้อยู่ในไคลเอนต์อย่างน้อยก็บนเซิร์ฟเวอร์ ข้อเท็จจริงที่ว่าคุณเลือกที่จะใช้ชื่อฟิลด์ที่เหมือนกับชื่อจากบริการบนเว็บเพียงตัวพิมพ์เล็กไม่ได้เปลี่ยนแปลงสิ่งนี้ ดังนั้นฉันขอแนะนำให้ทำสิ่งนี้:
var myObj = {
field1: theirObj.FIELD1,
field2: theirObj.FIELD2,
(etc)
}
แน่นอนฉันตั้งสมมติฐานทุกอย่างที่นี่ซึ่งอาจไม่เป็นจริง หากสิ่งนี้ใช้ไม่ได้กับคุณหรือช้าเกินไป (ใช่หรือไม่ฉันยังไม่ได้ทดสอบ แต่ฉันจินตนาการว่าความแตกต่างเล็กลงเมื่อจำนวนของฟิลด์เพิ่มขึ้น) โปรดเพิกเฉยต่อสิ่งเหล่านี้ทั้งหมด :)
หากคุณไม่ต้องการทำสิ่งนี้และสนับสนุนเบราว์เซอร์บางตัวเท่านั้นคุณสามารถใช้ getters ใหม่เพื่อส่งคืน "ตัวพิมพ์ใหญ่ (ฟิลด์)": ดูhttp://robertnyman.com/2009/05/28 / getters-and-setters-with-javascript-code-samples-and-demos /และลิงก์ในหน้านั้นสำหรับข้อมูลเพิ่มเติม
แก้ไข:
เหลือเชื่อนี่ก็เร็วเป็นสองเท่าอย่างน้อยก็ที่ FF3.5 ของฉันในที่ทำงาน ดู: http://jsperf.com/spiny001
แม้ว่านี่จะไม่ได้เป็นทางออกที่ดีกว่าในการเปลี่ยนชื่อคีย์ แต่ก็มีวิธี ES6 ที่ง่ายและรวดเร็วในการเปลี่ยนชื่อคีย์ทั้งหมดในวัตถุในขณะที่ไม่ทำการปิดบังข้อมูลที่มีอยู่
let b = {a: ["1"], b:["2"]};
Object.keys(b).map(id => {
b[`root_${id}`] = [...b[id]];
delete b[id];
});
console.log(b);
โซลูชันบางอย่างที่ระบุไว้ในหน้านี้มีผลข้างเคียง:
นี่คือวิธีแก้ปัญหาที่ช่วยให้ตำแหน่งของคีย์อยู่ในที่เดียวกันและเข้ากันได้กับ 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 อาจไม่รองรับแต่ละโหมดในโหมดเข้มงวด
นี่คือตัวอย่างในการสร้างวัตถุใหม่ด้วยปุ่มเปลี่ยนชื่อ
let x = { id: "checkout", name: "git checkout", description: "checkout repository" };
let renamed = Object.entries(x).reduce((u, [n, v]) => {
u[`__${n}`] = v;
return u;
}, {});
อีกวิธีหนึ่งด้วยวิธี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);
นี่คือการดัดแปลงเล็กน้อยที่ฉันทำกับฟังก์ชั่นของ Bomber เพื่อให้สามารถใช้ Array of Objects แทนวัตถุเพียงอย่างเดียวและคุณสามารถเปิดใช้งานดัชนี นอกจากนี้ "คีย์" สามารถกำหนดโดยอาร์เรย์
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);
ในความคิดของฉัน แต่คุณจะจบลงด้วยกุญแจที่เรียงลำดับใหม่ คีย์ที่สร้างขึ้นใหม่จะถูกต่อท้าย ฉันรู้ว่าคุณไม่ควรพึ่งพาคำสั่งซื้อที่สำคัญ แต่ถ้าคุณต้องการที่จะรักษามันคุณจะต้องผ่านกุญแจทั้งหมดและสร้างวัตถุใหม่ทีละคนเปลี่ยนกุญแจในคำถามในระหว่างกระบวนการนั้น
แบบนี้:
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' };
ลองใช้ในเครื่องมือแก้ไขที่คุณชื่นชอบ <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
}