我有一个超类,它是许多子类(Customer, Product, ProductCategory…)的父类(Entity)。
我想在Typescript中动态克隆一个包含不同子对象的对象。
例如:拥有不同产品的客户拥有一个ProductCategory
var cust:Customer = new Customer ();
cust.name = "someName";
cust.products.push(new Product(someId1));
cust.products.push(new Product(someId2));
为了克隆对象的整个树,我在实体中创建了一个函数
public clone():any {
var cloneObj = new this.constructor();
for (var attribut in this) {
if(typeof this[attribut] === "object"){
cloneObj[attribut] = this.clone();
} else {
cloneObj[attribut] = this[attribut];
}
}
return cloneObj;
}
当new被转译为javascript时,将引发以下错误:错误TS2351:不能对缺少调用或构造签名的表达式使用'new'。
虽然脚本工作,但我想摆脱转译错误
使用扩展运算符…
Const obj1 ={参数:"value"};
Const obj2 ={…其中obj1};
展开运算符将obj1中的所有字段展开到obj2上。在结果中,您将获得具有新引用的新对象和与原始对象相同的字段。
记住,这是浅复制,这意味着如果对象是嵌套的,那么它的嵌套复合参数将通过相同的引用存在于新对象中。
Object.assign ()
Const obj1={参数:"value"};
const obj2:any =对象。分配({},其中obj1);
对象。赋值创建真实的副本,但只有自己的属性,因此原型中的属性将不存在于被复制的对象中。这也是浅拷贝。
Object.create ()
Const obj1={参数:"value"};
const obj2:any = Object.create(obj1);
对象。Create不是做真正的克隆,它是从原型创建对象。因此,如果对象应该克隆主类型属性,请使用它,因为主类型属性的赋值不是通过引用完成的。
对象的优点。Create是指在prototype中声明的任何函数都可以在我们新创建的对象中使用。
关于浅复制的一些事情
浅拷贝将旧对象的所有字段放入新对象中,但这也意味着如果原始对象具有复合类型字段(对象,数组等),那么这些字段将放入具有相同引用的新对象中。原物体中这种磁场的突变会在新物体中反映出来。
这可能看起来像一个陷阱,但真正需要复制整个复杂对象的情况是罕见的。浅拷贝将重用大部分内存,这意味着与深拷贝相比非常便宜。
深拷贝
展开运算符可以方便地进行深度复制。
const obj1 = { param: "value", complex: { name: "John"}}
const obj2 = { ...obj1, complex: {...obj1.complex}};
上面的代码创建了obj1的深度拷贝。复合字段“complex”也被复制到obj2中。突变字段“复杂”不会反映副本。
通过在TypeScript 2.1中引入的“Object Spread”,很容易获得一个浅拷贝
this TypeScript: let copy ={…原始};
生成这个JavaScript:
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
var copy = __assign({}, original);
https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html
解决具体问题
你可以使用类型断言来告诉编译器你知道的更好:
public clone(): any {
var cloneObj = new (this.constructor() as any);
for (var attribut in this) {
if (typeof this[attribut] === "object") {
cloneObj[attribut] = this[attribut].clone();
} else {
cloneObj[attribut] = this[attribut];
}
}
return cloneObj;
}
克隆
截至2022年,有一项提案允许structuredClone深度复制许多类型。
const copy = structuredClone(value)
对于你可以在什么事情上使用它有一些限制。
请记住,有时候编写自己的映射比完全动态的映射更好。然而,你可以使用一些“克隆”技巧来获得不同的效果。
我将使用以下代码的所有后续示例:
class Example {
constructor(public type: string) {
}
}
class Customer {
constructor(public name: string, public example: Example) {
}
greet() {
return 'Hello ' + this.name;
}
}
var customer = new Customer('David', new Example('DavidType'));
选择1:分散
属性:是的
方法:没有
深度复制:否
var clone = { ...customer };
alert(clone.name + ' ' + clone.example.type); // David DavidType
//alert(clone.greet()); // Not OK
clone.name = 'Steve';
clone.example.type = 'SteveType';
alert(customer.name + ' ' + customer.example.type); // David SteveType
选项2:Object.assign
属性:是的
方法:没有
深度复制:否
var clone = Object.assign({}, customer);
alert(clone.name + ' ' + clone.example.type); // David DavidType
alert(clone.greet()); // Not OK, although compiler won't spot it
clone.name = 'Steve';
clone.example.type = 'SteveType';
alert(customer.name + ' ' + customer.example.type); // David SteveType
选项3:Object.create
属性:继承
方法:继承
深度复制:浅继承(深度更改同时影响原始和克隆)
var clone = Object.create(customer);
alert(clone.name + ' ' + clone.example.type); // David DavidType
alert(clone.greet()); // OK
customer.name = 'Misha';
customer.example = new Example("MishaType");
// clone sees changes to original
alert(clone.name + ' ' + clone.example.type); // Misha MishaType
clone.name = 'Steve';
clone.example.type = 'SteveType';
// original sees changes to clone
alert(customer.name + ' ' + customer.example.type); // Misha SteveType
选项4:深度复制功能
属性:是的
方法:没有
深度复制:是的
function deepCopy(obj) {
var copy;
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = deepCopy(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = deepCopy(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
}
var clone = deepCopy(customer) as Customer;
alert(clone.name + ' ' + clone.example.type); // David DavidType
// alert(clone.greet()); // Not OK - not really a customer
clone.name = 'Steve';
clone.example.type = 'SteveType';
alert(customer.name + ' ' + customer.example.type); // David DavidType