如何使用ES6克隆Javascript类实例。
我对基于jquery或$ extend的解决方案不感兴趣。
我看到过很多有关对象克隆的讨论,这些讨论表明问题很复杂,但是使用ES6时,它本身就可以提供一个非常简单的解决方案-我将其放在下面,看看人们是否认为它令人满意。
编辑:有人建议我的问题是重复的;我看到了这个答案,但它已有7年历史,并且使用ES6之前的js涉及非常复杂的答案。我建议我的问题(允许使用ES6)有一个非常简单的解决方案。
如何使用ES6克隆Javascript类实例。
我对基于jquery或$ extend的解决方案不感兴趣。
我看到过很多有关对象克隆的讨论,这些讨论表明问题很复杂,但是使用ES6时,它本身就可以提供一个非常简单的解决方案-我将其放在下面,看看人们是否认为它令人满意。
编辑:有人建议我的问题是重复的;我看到了这个答案,但它已有7年历史,并且使用ES6之前的js涉及非常复杂的答案。我建议我的问题(允许使用ES6)有一个非常简单的解决方案。
Object
用作数据持有人的pure 。这是关于ES6 class
es和不丢失类类型信息的问题。它需要一个不同的解决方案。
Answers:
这很复杂; 我尝试了很多!最后,这种单行代码适用于我的自定义ES6类实例:
let clone = Object.assign(Object.create(Object.getPrototypeOf(orig)), orig)
它避免设置原型,因为他们说这会大大降低代码速度。
它支持符号,但不适用于getter / setter方法,并且不适用于不可枚举的属性(请参见Object.assign()docs)。另外,可悲的是,克隆基本内部类(例如Array,Date,RegExp,Map等)似乎经常需要一些单独的处理。
结论:这是一团糟。希望有一天将提供本机且干净的克隆功能。
const clone = Object.assign( {}, instanceOfBlah );
Object.setPrototypeOf( clone, Blah.prototype );
注意Object.assign的特征:它执行浅表复制,并且不复制类方法。
如果您想要深层副本或对副本有更多控制,则可以使用lodash克隆功能。
Object.create
使用指定的原型创建了新对象,所以为什么不这样做const clone = Object.assign(Object.create(instanceOfBlah), instanceOfBlah)
。同样,类方法也将被复制。
Blah.prototype != instanceOfBlah
。您应该使用Object.getPrototypeOf(instanceOfBlah)
不建议扩展Prototype,这将在您对代码/组件进行测试时导致问题。单元测试框架不会自动采用您的原型扩展。因此,这不是一个好习惯。这里有更多有关原型扩展的解释,为什么扩展本机对象是一种不好的做法?
要在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():
结果:卡西欧·塞弗林
clone.logFullName():
结果:约翰·塞弗林
original.address.street;
结果:'Street B,99'//注意原始子对象已更改
注意:如果实例具有闭包作为其自己的属性,则此方法将不会包装它。(阅读有关闭包的更多信息)而且,子对象“地址”将不会被克隆。
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或下划线。他们将创建一个新对象,并将每个值从原始对象复制到新对象,并将其引用保存在内存中。
下划线:let cloneUnderscore = _(原始).clone();
Loadash克隆:var cloneLodash = _.cloneDeep(原始);
lodash或下划线的缺点是需要在项目中包括一些额外的库。但是,它们是不错的选择,并且还会产生高性能的结果。
{}
,克隆不会继承原始对象的任何原型方法。clone.logFullName()
根本无法工作。在Object.assign( Object.create(Object.getPrototypeOf(eOriginal)), eOriginal)
你已经被罚款之前,你为什么要改变这种状况?
Object.assign({},original)
,它不起作用。
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;
}, {});