cloning object
I have a super class that is the parent ( Entity
) for many subclass ( Customer
, Product
, ProductCategory
...)
I'm looking to clone dynamically an object that contains different sub objects in Typescript.
In example : a Customer
that has different Product
who has a ProductCategory
var cust:Customer = new Customer ();
cust.name = "someName";
cust.products.push(new Product(someId1));
cust.products.push(new Product(someId2));
In order to clone the whole tree of object I created a function in Entity
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;
}
The new
rises the following error when it is transpiled to javascript: error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
Although the script works, I would like to get rid of the transpiled error
Solving The Specific Issue
You can use a type assertion to tell the compiler that you know better:
public clone(): any {
var cloneObj = new (<any>this.constructor());
for (var attribut in this) {
if (typeof this[attribut] === "object") {
cloneObj[attribut] = this.clone();
} else {
cloneObj[attribut] = this[attribut];
}
}
return cloneObj;
}
Cloning
Bear in mind that sometimes it is better to write your own mapping - rather than being totally dynamic. However, there are a few "cloning" tricks you can use that give you difference effects.
I will use the following code for all the subsequent examples:
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'));
Option 1: Spread
Properties: Yes Methods: No Deep Copy: No
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
Option 2: Object.assign
Properties: Yes Methods: No Deep Copy: No
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
Option 3: Object.create
Properties: Yes Methods: Yes Deep Copy: No
var clone = Object.create(customer);
alert(clone.name + ' ' + clone.example.type); // David DavidType
alert(clone.greet()); // OK
clone.name = 'Steve';
clone.example.type = 'SteveType';
alert(customer.name + ' ' + customer.example.type); // David SteveType
Option 4: Deep Copy Function
Properties: Yes Methods: No Deep Copy: Yes
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 = <Customer>deepCopy(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
1.Use spread operator
const obj1 = { param: "value" };
const obj2 = { ...obj1 };
Spread operator takes all fields from obj1 and spread them over obj2. In the result you get new object with new reference and the same fields as original one.
Remember that it is shallow copy, it means that if object is nested then its nested composite params will exists in the new object by the same reference.
2.Object.assign()
const obj1={ param: "value" };
const obj2:any = Object.assign({}, obj1);
Object.assign create real copy, but only own properties, so properties in prototype will not exist in copied object. It is also shallow copy.
3.Object.create()
const obj1={ param: "value" };
const obj2:any = Object.create(obj1);
Object.create
is not doing real cloning , it is creating object from prototype. So use it if the object should clone primary type properties, because primary type properties assignment is not done by reference.
Pluses of Object.create are that any functions declared in prototype will be available in our newly created object.
Few things about shallow copy
Shallow copy puts into new object all fields of the old one, but it also means that if original object has composite type fields (object, arrays etc.) then those fields are put in new object with the same references. Mutation such field in original object will be reflected in new object.
It maybe looks like a pitfall, but really situation when the whole complex object needs to be copied is rare. Shallow copy will re-use most of memory which means that is very cheap in comparison to deep copy.
Deep copy
Spread operator can be handy for deep copy.
const obj1 = { param: "value", complex: { name: "John"}}
const obj2 = { ...obj1, complex: {...obj1.complex}};
Above code created deep copy of obj1. Composite field "complex" was also copied into obj2. Mutation field "complex" will not reflect the copy.
It's easy to get a shallow copy with "Object Spread" introduced in TypeScript 2.1
this TypeScript: let copy = { ...original };
produces this 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
链接地址: http://www.djcxy.com/p/40682.html上一篇: 在TypeScript中获取并设置
下一篇: 克隆对象