TLDR;
// Use this approach
//Method 1 - clone will inherit the prototype methods of the original.
let cloneWithPrototype = Object.assign(Object.create(Object.getPrototypeOf(original)), original);
在 Javascript 中,不建议对原型进行扩展,当您对代码/组件进行测试时会导致问题。单元测试框架不会自动假设您的原型扩展。所以这不是一个好习惯。
这里有更多关于原型扩展的解释Why is extending native objects a bad practice?
在 JavaScript 中克隆对象没有简单或直接的方法。这是使用“浅拷贝”的第一个实例:
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');
//Method 1 - clone will inherit the prototype methods of the original.
let cloneWithPrototype = Object.assign(Object.create(Object.getPrototypeOf(original)), original);
//Method 2 - object.assing() will not clone the Prototype.
let cloneWithoutPrototype = Object.assign({},original);
//Method 3 - the same of object assign but shorter syntax using "spread operator"
let clone3 = { ...original };
//tests
cloneWithoutPrototype.firstName = 'John';
cloneWithoutPrototype.address.street = 'Street B, 99'; //will not be cloned
结果:
original.logFullName();
结果:Cassio Seffrin
cloneWithPrototype.logFullName();
结果:Cassio Seffrin
original.address.street;
result: 'Street B, 99' // 注意原来的子对象被改变了
注意:如果实例有闭包作为自己的属性,则此方法不会包装它。 (read more about closures) 而且,子对象“地址”不会被克隆。
cloneWithoutPrototype.logFullName()
不会工作。克隆不会继承原始的任何原型方法。
cloneWithPrototype.logFullName()
会起作用,因为克隆也会复制它的原型。
使用 Object.assign 克隆数组:
let cloneArr = array.map((a) => Object.assign({}, a));
使用 ECMAScript spread sintax 克隆数组:
let cloneArrSpread = array.map((a) => ({ ...a }));
2 -> 深度克隆:
要归档一个全新的对象引用,我们可以使用 JSON.stringify() 将原始对象解析为字符串,然后将其解析回 JSON.parse()。
let deepClone = JSON.parse(JSON.stringify(original));
使用深度克隆,将保留对地址的引用。但是 deepClone 原型将会丢失,因此 deepClone.logFullName() 将不起作用。
3 -> 第三方库:
另一个选项是使用第三方库,如 loadash 或 underscore。
他们将创建一个新对象并将每个值从原始对象复制到新对象,并将其引用保存在内存中。
下划线:
让 cloneUnderscore = _(original).clone();
Loadash 克隆:
var cloneLodash = _.cloneDeep(original);
lodash 或 underscore 的缺点是需要在您的项目中包含一些额外的库。然而,它们是不错的选择,而且还能产生高性能的结果。