Googling สำหรับ "javascript clone object" นำผลลัพธ์ที่แปลกจริง ๆ มาใช้บางอันล้าสมัยอย่างสิ้นหวังและบางอันก็ซับซ้อนเกินไปไม่ง่ายเหมือน:
let clone = {...original};
มีอะไรผิดปกติกับเรื่องนี้หรือไม่?
Googling สำหรับ "javascript clone object" นำผลลัพธ์ที่แปลกจริง ๆ มาใช้บางอันล้าสมัยอย่างสิ้นหวังและบางอันก็ซับซ้อนเกินไปไม่ง่ายเหมือน:
let clone = {...original};
มีอะไรผิดปกติกับเรื่องนี้หรือไม่?
คำตอบ:
นี้เป็นสิ่งที่ดีสำหรับการโคลนตื้น การแพร่กระจายของวัตถุเป็นส่วนหนึ่งของมาตรฐาน ECMAScript 2018
สำหรับการโคลนนิ่งแบบลึกคุณจะต้องมีโซลูชันอื่น
const clone = {...original}
โคลนที่ตื้น
const newobj = {...original, prop: newOne}
การเพิ่มเสาอีกอันหนึ่งให้กับรูปแบบเดิมและเก็บไว้เป็นวัตถุใหม่
JSON.parse(JSON.stringify(input))
JSON.parse(JSON.stringify(input))
จะไม่ทำงานเพราะหากมี functions
หรือinfinity
เป็นค่าก็จะมอบหมายnull
ในสถานที่ของพวกเขา มันจะทำงานหากค่าที่มีความเรียบง่ายเป็นและไม่ได้literals
functions
แก้ไข: เมื่อคำตอบนี้ถูกโพสต์, {...obj}
ไวยากรณ์ไม่สามารถใช้ได้ในเบราว์เซอร์ส่วนใหญ่ ทุกวันนี้คุณควรใช้มันให้ดี (เว้นแต่คุณจะต้องรองรับ IE 11)
ใช้ Object.assign
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
อย่างไรก็ตามสิ่งนี้จะไม่ทำการโคลนแบบลึก ยังไม่มีวิธีการโคลนแบบพื้นเมืองในขณะนี้
แก้ไข: ตามที่ @Mike 'Pomax' Kamermans ที่กล่าวถึงในความคิดเห็นคุณสามารถโคลนวัตถุง่าย ๆ ได้ (เช่นไม่มีต้นแบบฟังก์ชันหรือการอ้างอิงแบบวงกลม) โดยใช้ JSON.parse(JSON.stringify(input))
JSON.parse(JSON.stringify(input))
เป็นโคลนลึกที่เหมาะสม อย่างไรก็ตามโมเมนต์ต้นแบบฟังก์ชันหรือการอ้างอิงแบบวงกลมอยู่ในระหว่างเล่นโซลูชันนั้นไม่ทำงานอีกต่อไป
หากวิธีการที่คุณใช้ทำงานได้ไม่ดีกับวัตถุที่เกี่ยวข้องกับชนิดข้อมูลเช่นวันที่ให้ลองวิธีนี้
นำเข้า _
import * as _ from 'lodash';
วัตถุโคลนนิ่งลึก
myObjCopy = _.cloneDeep(myObj);
import _ from 'lodash';
ก็เพียงพอ แต่ +1 สำหรับคำตอบ "อย่าปรับแต่งวงล้อ"
หากคุณไม่ต้องการใช้ json.parse (json.stringify (object)) คุณสามารถสร้างสำเนาคีย์ - ค่าแบบเรียกซ้ำ:
function copy(item){
let result = null;
if(!item) return result;
if(Array.isArray(item)){
result = [];
item.forEach(element=>{
result.push(copy(element));
});
}
else if(item instanceof Object && !(item instanceof Function)){
result = {};
for(let key in item){
if(key){
result[key] = copy(item[key]);
}
}
}
return result || item;
}
แต่วิธีที่ดีที่สุดคือการสร้างคลาสที่สามารถคืนค่าโคลนของมันเอง
class MyClass{
data = null;
constructor(values){ this.data = values }
toString(){ console.log("MyClass: "+this.data.toString(;) }
remove(id){ this.data = data.filter(d=>d.id!==id) }
clone(){ return new MyClass(this.data) }
}
ต่อจากคำตอบโดย @marcel ฉันพบว่าบางฟังก์ชั่นยังคงหายไปในวัตถุที่ถูกโคลน เช่น
function MyObject() {
var methodAValue = null,
methodBValue = null
Object.defineProperty(this, "methodA", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
},
enumerable: true
});
Object.defineProperty(this, "methodB", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
}
});
}
ที่ MyObject ฉันสามารถโคลน methodA แต่ methodB ได้รับการยกเว้น สิ่งนี้เกิดขึ้นเพราะมันหายไป
enumerable: true
ซึ่งหมายความว่ามันไม่ปรากฏใน
for(let key in item)
แต่ฉันเปลี่ยนไปเป็น
Object.getOwnPropertyNames(item).forEach((key) => {
....
});
ซึ่งจะรวมถึงคีย์ที่ไม่สามารถนับได้
ฉันก็พบว่าต้นแบบ ( โปรโต ) ไม่ได้ถูกโคลน สำหรับที่ฉันลงเอยด้วยการใช้
if (obj.__proto__) {
copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}
PS: น่าผิดหวังที่ฉันไม่สามารถหาฟังก์ชั่นในตัวเพื่อทำสิ่งนี้
คุณสามารถทำสิ่งนี้ได้เช่นกัน
let copiedData = JSON.parse(JSON.stringify(data));
We can do that with two way:
1- First create a new object and replicate the structure of the existing one by iterating
over its properties and copying them on the primitive level.
let user = {
name: "John",
age: 30
};
let clone = {}; // the new empty object
// let's copy all user properties into it
for (let key in user) {
clone[key] = user[key];
}
// now clone is a fully independant clone
clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object
2- Second we can use the method Object.assign for that
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);
-Another example
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
It copies all properties of user into the empty object and returns it. Actually, the same as the loop, but shorter.
แต่ Object.assign () ไม่สร้างการโคลนแบบลึก
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, same object
// user and clone share sizes
user.sizes.width++; // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one
ในการแก้ไขปัญหานั้นเราควรใช้การวนลูปที่ตรวจสอบแต่ละค่าของผู้ใช้ [คีย์] และถ้าเป็นวัตถุให้ทำซ้ำโครงสร้างของมันเช่นกัน ที่เรียกว่า "การโคลนนิ่งลึก"
มีขั้นตอนวิธีการมาตรฐานสำหรับการโคลนลึกเป็นเรื่องที่จับกรณีดังกล่าวข้างต้นและกรณีที่ซับซ้อนมากขึ้นเรียกว่าโครงสร้างขั้นตอนวิธีการโคลน เพื่อไม่ให้บูรณาการล้อเราสามารถใช้การดำเนินการในการทำงานของมันจากห้องสมุด JavaScript lodashวิธีการที่เรียกว่า_.cloneDeep (obj)
วิธีการทั้งหมดข้างต้นไม่สามารถจัดการกับการโคลนนิ่งของวัตถุที่อยู่ในระดับ n ฉันไม่ได้ตรวจสอบประสิทธิภาพของมันเหนือคนอื่น ๆ แต่มันสั้นและง่าย
ตัวอย่างแรกด้านล่างแสดงการโคลนวัตถุโดยใช้Object.assign
โคลนใดจนถึงระดับแรก
var person = {
name:'saksham',
age:22,
skills: {
lang:'javascript',
experience:5
}
}
newPerson = Object.assign({},person);
newPerson.skills.lang = 'angular';
console.log(newPerson.skills.lang); //logs Angular
การใช้วัตถุโคลนนิ่งแบบลึกเข้าใกล้ด้านล่าง
var person = {
name:'saksham',
age:22,
skills: {
lang:'javascript',
experience:5
}
}
anotherNewPerson = JSON.parse(JSON.stringify(person));
anotherNewPerson.skills.lang = 'angular';
console.log(person.skills.lang); //logs javascript
original = { a: [1,2,3] }
ช่วยให้คุณโคลนที่มีตัวอักษรเป็นclone.a
original.a
การปรับเปลี่ยนอย่างใดอย่างหนึ่งclone
หรือoriginal
ปรับเปลี่ยนสิ่งเดียวกันดังนั้นไม่นี่คือไม่ดี =)