typescript-복제 객체
I는 슈퍼 클래스가 부모 ( Entity
많은 서브 클래스) ( Customer
, Product
, ProductCategory
...)
Typescript에 다른 하위 객체가 포함 된 객체를 동적으로 복제하려고합니다.
예 : Customer
다른 Product
사람을 가진 사람ProductCategory
var cust:Customer = new Customer ();
cust.name = "someName";
cust.products.push(new Product(someId1));
cust.products.push(new Product(someId2));
객체의 전체 트리를 복제하기 위해 함수를 만들었습니다. 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;
}
는 new
이 자바 스크립트에 transpiled되어 다음과 같은 오류가 상승 :error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
스크립트가 작동하지만 변환 된 오류를 제거하고 싶습니다.
특정 문제 해결
형식 어설 션을 사용하여 컴파일러에 더 잘 알 수 있습니다.
public clone(): any {
var cloneObj = new (<any>this.constructor());
for (var attribut in this) {
if (typeof this[attribut] === "object") {
cloneObj[attribut] = this[attribut].clone();
} else {
cloneObj[attribut] = this[attribut];
}
}
return cloneObj;
}
클로닝
때로는 완전히 역동적이지 않고 자신 만의 매핑을 작성하는 것이 좋습니다. 그러나 차이 효과를주는 몇 가지 "복제"트릭이 있습니다.
모든 후속 예제에 다음 코드를 사용합니다.
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
clone.name = 'Steve';
clone.example.type = 'SteveType';
alert(customer.name + ' ' + customer.example.type); // David 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 = <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. 스프레드 연산자 사용
const obj1 = { param: "value" };
const obj2 = { ...obj1 };
스프레드 연산자는 obj1에서 모든 필드를 가져 와서 obj2에 펼칩니다. 결과적으로 새로운 참조 및 원래 필드와 동일한 필드를 가진 새 개체를 얻게됩니다.
얕은 사본이므로, 객체가 중첩 된 경우 중첩 된 복합 매개 변수가 동일한 참조에 의해 새 객체에 존재 함을 의미합니다.
2. Object.assign ()
const obj1={ param: "value" };
const obj2:any = Object.assign({}, obj1);
Object.assign은 실제 사본을 작성하지만 고유 한 특성 만 작성하므로 프로토 타입의 특성은 복사 된 오브젝트에 존재하지 않습니다. 얕은 사본이기도합니다.
3.Object.create ()
const obj1={ param: "value" };
const obj2:any = Object.create(obj1);
Object.create
실제 복제를 수행하지 않고 프로토 타입에서 객체를 생성합니다. 따라서 기본 유형 속성 지정은 참조로 수행되지 않으므로 오브젝트가 기본 유형 특성을 복제해야하는 경우이를 사용하십시오.
Object.create 의 장점 은 프로토 타입에 선언 된 모든 함수를 새로 만든 객체에서 사용할 수 있다는 것입니다.
얕은 사본에 대한 몇 가지
얕은 복사는 이전 객체의 모든 필드를 새 객체에 넣지 만 원본 객체에 복합 유형 필드 (객체, 배열 등)가있는 경우 해당 필드는 동일한 참조를 가진 새 객체에 저장됩니다. 원래 객체에서 이러한 필드를 변경하면 새 객체에 반영됩니다.
함정처럼 보일 수도 있지만 복잡한 객체 전체를 복사해야하는 상황은 거의 없습니다. 얕은 사본은 대부분의 메모리를 재사용하므로 이는 깊은 사본에 비해 매우 저렴합니다.
딥 카피
스프레드 연산자는 딥 카피에 유용 할 수 있습니다.
const obj1 = { param: "value", complex: { name: "John"}}
const obj2 = { ...obj1, complex: {...obj1.complex}};
위의 코드는 obj1의 깊은 복사본을 만들었습니다. 복합 필드 "복합"도 obj2에 복사되었습니다. 돌연변이 필드 "복합체"에는 복사본이 반영되지 않습니다.
이 시도:
let copy = (JSON.parse(JSON.stringify(objectToCopy)));
매우 큰 객체를 사용하거나 객체에 직렬화 할 수없는 속성이있을 때까지 좋은 솔루션입니다.
형식 안전성을 유지하기 위해 복사하려는 클래스에서 복사 기능을 사용할 수 있습니다.
getCopy(): YourClassName{
return (JSON.parse(JSON.stringify(this)));
}
또는 정적 방식으로 :
static createCopy(objectToCopy: YourClassName): YourClassName{
return (JSON.parse(JSON.stringify(objectToCopy)));
}
Typescript / Javascript에는 얕은 복제를위한 자체 연산자가 있습니다.
let shallowClone = { ...original };
TypeScript 2.1에 도입 된 "Object Spread"를 사용하면 간단하게 사본을 얻을 수 있습니다.
이 TypeScript : let copy = { ...original };
이 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
직렬화 가능 딥 클론의 경우 유형 정보는 다음과 같습니다.
export function clone<T>(a: T): T {
return JSON.parse(JSON.stringify(a));
}
다음과 같은 것을 가질 수도 있습니다.
class Entity {
id: number;
constructor(id: number) {
this.id = id;
}
clone(): this {
return new (this.constructor as typeof Entity)(this.id) as this;
}
}
class Customer extends Entity {
name: string;
constructor(id: number, name: string) {
super(id);
this.name = name;
}
clone(): this {
return new (this.constructor as typeof Customer)(this.id, this.name) as this;
}
}
clone
모든 Entity
서브 클래스 에서 메소드 를 대체하는지 확인하십시오. 그렇지 않으면 부분 복제가 발생합니다.
의 반환 유형 this
은 항상 인스턴스 유형과 일치합니다.
내가 받아
Object.assign(...)
속성 만 복사하면 프로토 타입과 메서드가 손실됩니다.
Object.create(...)
속성을 복사하지 않고 프로토 타입을 만드는 것입니다.
나를 위해 일한 Object.create(...)
것은 다음을 사용하여 속성을 사용 하고 속성을 복사 하는 프로토 타입을 만드는 것입니다 Object.assign(...)
.
따라서 객체의 foo
경우 다음과 같이 복제하십시오.
Object.assign(Object.create(foo), foo)
이 오류가 발생하면 :
TypeError: this.constructor(...) is not a function
이것은 올바른 스크립트입니다.
public clone(): any {
var cloneObj = new (<any>this.constructor)(); // line fixed
for (var attribut in this) {
if (typeof this[attribut] === "object") {
cloneObj[attribut] = this[attribut].clone();
} else {
cloneObj[attribut] = this[attribut];
}
}
return cloneObj;
}
이 문제를 직접 겪고 결국 추상 클래스를 제공하는 작은 라이브러리 cloneable-ts 를 작성하여 클래스를 확장하는 클래스에 클론 메소드를 추가합니다. 추상 클래스는 펜톤 만 교체하여 허용 대답에 설명 된 깊은 복사 기능 빌려 copy = {};
와 copy = Object.create(originalObj)
원본 객체의 클래스를 유지하기를. 다음은 클래스 사용 예입니다.
import {Cloneable, CloneableArgs} from 'cloneable-ts';
// Interface that will be used as named arguments to initialize and clone an object
interface PersonArgs {
readonly name: string;
readonly age: number;
}
// Cloneable abstract class initializes the object with super method and adds the clone method
// CloneableArgs interface ensures that all properties defined in the argument interface are defined in class
class Person extends Cloneable<TestArgs> implements CloneableArgs<PersonArgs> {
readonly name: string;
readonly age: number;
constructor(args: TestArgs) {
super(args);
}
}
const a = new Person({name: 'Alice', age: 28});
const b = a.clone({name: 'Bob'})
a.name // Alice
b.name // Bob
b.age // 28
또는 Cloneable.clone
도우미 메소드를 사용할 수도 있습니다 .
import {Cloneable} from 'cloneable-ts';
interface Person {
readonly name: string;
readonly age: number;
}
const a: Person = {name: 'Alice', age: 28};
const b = Cloneable.clone(a, {name: 'Bob'})
a.name // Alice
b.name // Bob
b.age // 28
구멍 객체 내용의 간단한 복제를 위해 인스턴스를 간단히 문자열 화하고 구문 분석합니다.
let cloneObject = JSON.parse(JSON.stringify(objectToClone))
objectToClone 트리에서 데이터를 변경하는 반면 cloneObject에는 변경이 없습니다. 그것은 나의 요구였다.
도움이되기를 바랍니다.
여기 매시업입니다! 그리고 여기에 StackBlitz 링크 가 있습니다. 현재 단순한 유형과 객체 유형을 복사하는 것으로 제한되어 있지만 쉽게 수정할 수 있다고 생각합니다.
let deepClone = <T>(source: T): { [k: string]: any } => {
let results: { [k: string]: any } = {};
for (let P in source) {
if (typeof source[P] === 'object') {
results[P] = deepClone(source[P]);
} else {
results[P] = source[P];
}
}
return results;
};
나는 일을 끝내었다.
public clone(): any {
const result = new (<any>this.constructor);
// some deserialization code I hade in place already...
// which deep copies all serialized properties of the
// object graph
// result.deserialize(this)
// you could use any of the usggestions in the other answers to
// copy over all the desired fields / properties
return result;
}
때문에:
var cloneObj = new (<any>this.constructor());
@Fenton에서 런타임 오류가 발생했습니다.
타이프 스크립트 버전 : 2.4.2
오래된 jQuery는 어떻습니까? 딥 클론은 다음과 같습니다.
var clone = $.extend(true, {}, sourceObject);
중첩 된 객체에 대한 유형을 유지하는 일반 복사 / 복제 서비스를 작성하는 데 착수했습니다. 내가 잘못하고 있다면 피드백을 좋아할 것이지만 지금까지는 효과가있는 것 같습니다 ...
import { Injectable } from '@angular/core';
@Injectable()
export class CopyService {
public deepCopy<T>(objectToClone: T): T {
// If it's a simple type or null, just return it.
if (typeof objectToClone === 'string' ||
typeof objectToClone === 'number' ||
typeof objectToClone === 'undefined' ||
typeof objectToClone === 'symbol' ||
typeof objectToClone === 'function' ||
typeof objectToClone === 'boolean' ||
objectToClone === null
) {
return objectToClone;
}
// Otherwise, check if it has a constructor we can use to properly instantiate it...
let ctor = Object.getPrototypeOf(objectToClone).constructor;
if (ctor) {
let clone = new ctor();
// Once we've instantiated the correct type, assign the child properties with deep copies of the values
Object.keys(objectToClone).forEach(key => {
if (Array.isArray(objectToClone[key]))
clone[key] = objectToClone[key].map(item => this.deepCopy(item));
else
clone[key] = this.deepCopy(objectToClone[key]);
});
if (JSON.stringify(objectToClone) !== JSON.stringify(clone))
console.warn('object cloned, but doesnt match exactly...\nobject: ' + JSON.stringify(objectToClone) + "\nclone: " + JSON.stringify(clone))
// return our cloned object...
return clone;
}
else {
//not sure this will ever get hit, but figured I'd have a catch call.
console.log('deep copy found something it didnt know: ' + JSON.stringify(objectToClone));
return objectToClone;
}
}
}
에 추가 "lodash.clonedeep": "^4.5.0"
하십시오 package.json
. 그런 다음 다음과 같이 사용하십시오.
import * as _ from 'lodash';
...
const copy = _.cloneDeep(original)
public clone(toClone: any): any {
const newClone = {};
for (const attribut in toClone) {
if (typeof toClone[attribut] === 'object') {
newClone[attribut] = this.clone(toClone[attribut]);
} else {
newClone[attribut] = toClone[attribut];
}
}
return newClone;
}
If you already have the target object, so you don't want to create it anew (like if updating an array) you must copy the properties.
If have done it this way:
Object.keys(source).forEach((key) => {
copy[key] = source[key]
})
Praise is due. (look at headline "version 2")
참고URL : https://stackoverflow.com/questions/28150967/typescript-cloning-object
'IT' 카테고리의 다른 글
키 저장소 및 별명에 비밀번호를 설정 한 적이 없으므로 어떻게 작성합니까? (0) | 2020.07.03 |
---|---|
원형 인 사용자 정의 UIView를 그리는 방법-iPhone 앱 (0) | 2020.07.03 |
Windows에서 명령 프롬프트를 사용하여 8080이 아닌 다른 포트에서 jenkins를 시작하는 방법은 무엇입니까? (0) | 2020.07.03 |
'AndroidJUnit4'기호를 확인할 수 없습니다 (0) | 2020.07.03 |
currentTimeMillis를 Java의 날짜로 변환하는 방법은 무엇입니까? (0) | 2020.07.03 |