我有一个超类,它是许多子类(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中。突变字段“复杂”不会反映副本。
使用扩展运算符…
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 3.7发布以来,现在支持递归类型别名,它允许我们定义一个类型安全的deepCopy()函数:
// DeepCopy type can be easily extended by other types,
// like Set & Map if the implementation supports them.
type DeepCopy<T> =
T extends undefined | null | boolean | string | number ? T :
T extends Function | Set<any> | Map<any, any> ? unknown :
T extends ReadonlyArray<infer U> ? Array<DeepCopy<U>> :
{ [K in keyof T]: DeepCopy<T[K]> };
function deepCopy<T>(obj: T): DeepCopy<T> {
// implementation doesn't matter, just use the simplest
return JSON.parse(JSON.stringify(obj));
}
interface User {
name: string,
achievements: readonly string[],
extras?: {
city: string;
}
}
type UncopiableUser = User & {
delete: () => void
};
declare const user: User;
const userCopy: User = deepCopy(user); // no errors
declare const uncopiableUser: UncopiableUser;
const uncopiableUserCopy: UncopiableUser = deepCopy(uncopiableUser); // compile time error
操场上