如何使用ES6克隆Javascript类实例。
我对基于jquery或$ extend的解决方案不感兴趣。
我已经看到对对象克隆的相当陈旧的讨论表明这个问题非常复杂,但是ES6提供了一个非常简单的解决方案 - 我会把它放在下面,看看人们是否认为它是令人满意的。
编辑:建议我的问题是重复的;我看到了这个答案,但它已经有7年的历史,并且使用前ES6 js涉及非常复杂的答案。我建议我的问题,允许ES6,有一个非常简单的解决方案。
答案 0 :(得分:64)
let clone = Object.assign( Object.create( Object.getPrototypeOf(orig)), orig)
我尝试了很多,最后这对我有用。
它还避免设置原型,因为they say它会大大减慢代码的速度。
它是一个单行!
答案 1 :(得分:7)
const clone = Object.assign( {}, instanceOfBlah );
Object.setPrototypeOf( clone, Blah.prototype );
请注意Object.assign的特征:它执行浅拷贝并且不复制类方法。
如果您想要对副本进行深层复制或更多控制,则可以使用lodash clone functions。
答案 2 :(得分:1)
不建议对Prototype进行扩展,这将在您对代码/组件进行测试时导致问题。单元测试框架不会自动采用您的原型扩展。因此,这不是一个好习惯。 Why is extending native objects a bad practice?
上有更多关于原型扩展的解释。要在JavaScript中克隆对象,没有简单或直接的方法。这是第一个使用“ Shallow Copy”的实例:
1->浅克隆:
class Employee {
constructor(first, last, street) {
this.firstName = first;
this.lastName = last;
this.address = { street: street };
}
logFullName() {
console.log(this.firstName + ' ' + this.lastName);
}
}
let original = new Employee('Cassio', 'Seffrin', 'Street A, 23');
let clone = Object.assign({},original); //object.assing() method
let cloneWithPrototype Object.create(Object.getPrototypeOf(original)), original) // the clone will inherit the prototype methods of the original.
let clone2 = { ...original }; // the same of object assign but shorter sintax using "spread operator"
clone.firstName = 'John';
clone.address.street = 'Street B, 99'; //will not be cloned
结果:
original.logFullName():
结果:Cassio Seffrin
clone.logFullName():
结果:John Seffrin
original.address.street;
结果:“ Street B,99” //注意原始子对象已更改
注意:如果实例将闭包作为自己的属性,则此方法将不包装它。 (read more about closures)而且,子对象“地址”将不会被克隆。
clone.logFullName()
不起作用。
cloneWithPrototype.logFullName()
将起作用,因为克隆也将复制其原型。
要使用Object.assign克隆阵列:
let cloneArr = array.map((a) => Object.assign({}, a));
使用ECMAScript传播正弦波克隆数组:
let cloneArrSpread = array.map((a) => ({ ...a }));
2->深度克隆:
要存档一个全新的对象引用,我们可以使用JSON.stringify()将原始对象解析为字符串,然后将其解析回JSON.parse()。
let deepClone = JSON.parse(JSON.stringify(original));
使用深度克隆时,将保留对地址的引用。但是deepClone原型将丢失,因此deepClone.logFullName()将不起作用。
3->第三方库:
另一个选择是使用第三方库,例如loadash或下划线。 他们将创建一个新对象,并将每个值从原始对象复制到新对象,并将其引用保存在内存中。
下划线: 让cloneUnderscore = _(原始).clone();
Loadash克隆: var cloneLodash = _.cloneDeep(原始);
lodash或下划线的缺点是需要在项目中包括一些额外的库。但是,它们是不错的选择,并且还会产生高性能的结果。
答案 3 :(得分:0)
另外一个班轮:
大多数时候...(适用于Date,RegExp,Map,String,Number,Array),btw,克隆字符串,数字有点有趣。
let clone = new obj.constructor(...[obj].flat())
对于那些没有复制构造函数的类:
let clone = Object.assign(new obj.constructor(...[obj].flat()), obj)
答案 4 :(得分:0)
class A {
constructor() {
this.x = 1;
}
y() {
return 1;
}
}
const a = new A();
const output = Object.getOwnPropertyNames(Object.getPrototypeOf(a)).concat(Object.getOwnPropertyNames(a)).reduce((accumulator, currentValue, currentIndex, array) => {
accumulator[currentValue] = a[currentValue];
return accumulator;
}, {});
答案 5 :(得分:0)
我几乎喜欢所有答案。我遇到了这个问题,要解决该问题,我将通过定义一个XMLDocument.setProperty("SelectionLanguage", "XPath")
方法来手动完成此操作,并在其中内部,我将从头开始构建整个对象。对我来说,这是有道理的,因为生成的对象自然会与克隆的对象属于同一类型。
打字稿示例:
=iferror(index(importrange("1HprNdu3RgOimFFkyqp5k3pC79m-YubH0jtT3jKgDxzU","TEAM SALES!$A:$DB"),
match($A3&$B3&$C3&$D3&$I3&$N3,importrange("1HprNdu3RgOimFFkyqp5k3pC79m-YubH0jtT3jKgDxzU","TEAM SALES!$A:$a")&
importrange("1HprNdu3RgOimFFkyqp5k3pC79m-YubH0jtT3jKgDxzU","TEAM SALES!$t:$t")&
importrange("1HprNdu3RgOimFFkyqp5k3pC79m-YubH0jtT3jKgDxzU","TEAM SALES!$Ab:$ab")&
importrange("1HprNdu3RgOimFFkyqp5k3pC79m-YubH0jtT3jKgDxzU","TEAM SALES!$b:$b")&
importrange("1HprNdu3RgOimFFkyqp5k3pC79m-YubH0jtT3jKgDxzU","TEAM SALES!$h:$h")&
importrange("1HprNdu3RgOimFFkyqp5k3pC79m-YubH0jtT3jKgDxzU","TEAM SALES!$n:$n"),0),
match(D3&" ROYALTY FINAL",importrange("1HprNdu3RgOimFFkyqp5k3pC79m-YubH0jtT3jKgDxzU","TEAM SALES!$1:$1"),0)),)
我喜欢这种解决方案,因为它看起来更“面向对象”
答案 6 :(得分:0)
使用与原始对象相同的原型和相同的属性创建对象的副本。
function clone(obj) {
return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj))
}
适用于不可枚举的属性、getter、setter 等。无法克隆许多内置 javascript 类型(例如数组、映射、代理)具有的内部插槽
答案 7 :(得分:0)
试试这个:
function copy(obj) {
//Edge case
if(obj == null || typeof obj !== "object") { return obj; }
var result = {};
var keys_ = Object.getOwnPropertyNames(obj);
for(var i = 0; i < keys_.length; i++) {
var key = keys_[i], value = obj[key];
result[key] = value;
}
Object.setPrototypeOf(result, obj.__proto__);
return result;
}
//test
function Point(x,y) {
this.x = x;
this.y = y;
}
var myPoint = new Point(0,1);
var copiedPoint = copy(myPoint);
console.log(
copiedPoint,
copiedPoint instanceof Point,
copiedPoint === myPoint
);
Object.getOwnPropertyNames
,因此它还会添加不可枚举的属性。
答案 8 :(得分:-3)
例如,如果您要克隆名为Obj的对象,则可以使用传播运算符:
let clone = { ...obj};
如果要更改或添加任何内容到克隆对象:
let clone = { ...obj, change: "something" };