typescript - 복제 개체
.Entity
의 서브클래스아부클래스에 Customer
,Product
,ProductCategory
...)
Typescript에 다른 하위 개체가 포함된 개체를 동적으로 복제하려고 합니다.
a: aCustomer
Product
who who who a a who who who 。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
합니다.javascript는 javascript로 변환됩니다.error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.
스크립트는 작동하지만, 전치된 오류를 제거하고 싶습니다.
특정 문제 해결
타입 어설션을 사용하여 컴파일러에 자신이 더 잘 알고 있음을 알릴 수 있습니다.
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
연산자 사용
...
const obj1 = { param: "value" }; const obj2 = { ...obj1 };
분산 연산자는 obj1에서 모든 필드를 가져와 obj2에 분산합니다.그 결과 새 참조를 가진 새 객체와 원래 참조와 동일한 필드가 생성됩니다.
얕은 복사이므로 객체가 중첩된 경우 중첩된 복합 매개 변수가 동일한 참조로 새 객체에 존재함을 의미합니다.
Object.assign()
const obj1={ param: "value" }; const obj2:any = Object.assign({}, obj1);
Object.assign은 실제 복사본을 생성하지만 속성만 소유하므로 프로토타입의 속성은 복사된 개체에 존재하지 않습니다.그것은 또한 얕은 복사이다.
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의 딥 카피를 작성했습니다.복합 필드 "complex"도 obj2에 복사되었습니다.변환 필드 "complex"는 복사본을 반영하지 않습니다.
이것을 시험해 보세요.
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에서 도입된 "개체 확산"을 사용하면 쉽게 복사본을 얻을 수 있습니다.
TypeScript: this this this this 。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));
}
"lodash.clonedeep": "^4.5.0"
your package.json
다음과 같이 그 후 다음과 같이 사용합니다.
import * as _ from 'lodash';
...
const copy = _.cloneDeep(original)
내 견해:
Object.assign(...)
속성만 복사하고 프로토타입과 메서드는 손실됩니다.
Object.create(...)
부동산 복사하는 게 아니라 프로토타입을 만드는 거예요.
를 본 하는 것입니다.Object.create(...)
이라고 할 수 있습니다.Object.assign(...)
:
그래서 어떤 오브젝트에 대해서foo
복제하다하다.
Object.assign(Object.create(foo), foo)
다음과 같은 것도 있습니다.
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
는 항상 인스턴스의 유형과 일치합니다.
이 에러가 발생했을 경우:
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;
}
데이터뿐만 아니라 메서드도 복사하려면 다음 방법을 따르십시오.
let copy = new BaseLayer() ;
Object.assign(copy, origin);
copy.x = 8 ; //will not affect the origin object
바꿔주세요.BaseLayer
컨스트럭터의 이름으로 변경해 주세요.
제 매쉬업 여기 있어요!여기 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;
};
spread 구문을 사용하여 할당을 파기할 수 있습니다.
var obj = {id = 1, name = 'product1'};
var clonedObject = {...obj};
TypeScript 3.7이 출시되었기 때문에 재귀형 에일리어스가 지원되므로 Type Safe를 정의할 수 있습니다.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
스스로 이 문제를 발견하고, 최종적으로 추상 클래스를 제공하는 작은 라이브러리 클론 가능-ts를 작성했습니다.이러한 클래스는 클론 메서드를 확장한 클래스에 추가합니다.추상 클래스는 Fenton이 승인한 답변에 설명된 딥 복사 기능을 차용합니다.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
typeScript에서 angular로 테스트하면 정상적으로 동작합니다.
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] = this.deepCopy(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = this.deepCopy(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
}
다른 개체, 어레이 등을 포함할 수 있는 개체를 자세히 복제하려면 다음을 사용합니다.
const clone = <T>(source: T): T => {
if (source === null) return source
if (source instanceof Date) return new Date(source.getTime()) as any
if (source instanceof Array) return source.map((item: any) => clone<any>(item)) as any
if (typeof source === 'object' && source !== {}) {
const clonnedObj = { ...(source as { [key: string]: any }) } as { [key: string]: any }
Object.keys(clonnedObj).forEach(prop => {
clonnedObj[prop] = clone<any>(clonnedObj[prop])
})
return clonnedObj as T
}
return source
}
용도:
const obj = {a: [1,2], b: 's', c: () => { return 'h'; }, d: null, e: {a:['x'] }}
const objClone = clone(obj)
다음은 다음을 설명하는 최신 구현입니다.Set
그리고.Map
또, 다음과 같습니다.
export function deepClone<T extends object>(value: T): T {
if (typeof value !== 'object' || value === null) {
return value;
}
if (value instanceof Set) {
return new Set(Array.from(value, deepClone)) as T;
}
if (value instanceof Map) {
return new Map(Array.from(value, ([k, v]) => [k, deepClone(v)])) as T;
}
if (value instanceof Date) {
return new Date(value) as T;
}
if (value instanceof RegExp) {
return new RegExp(value.source, value.flags) as T;
}
return Object.keys(value).reduce((acc, key) => {
return Object.assign(acc, { [key]: deepClone(value[key]) });
}, (Array.isArray(value) ? [] : {}) as T);
}
테스트 중:
deepClone({
test1: { '1': 1, '2': {}, '3': [1, 2, 3] },
test2: [1, 2, 3],
test3: new Set([1, 2, [1, 2, 3]]),
test4: new Map([['1', 1], ['2', 2], ['3', 3]])
});
test1:
1: 1
2: {}
3: [1, 2, 3]
test2: Array(3)
0: 1
1: 2
2: 3
test3: Set(3)
0: 1
1: 2
2: [1, 2, 3]
test4: Map(3)
0: {"1" => 1}
1: {"2" => 2}
2: {"3" => 3}
여기 있습니다deepCopy
TypeScript에서의 실장(아니오)any
코드에 포함되어 있습니다).
const deepCopy = <T, U = T extends Array<infer V> ? V : never>(source: T ): T => {
if (Array.isArray(source)) {
return source.map(item => (deepCopy(item))) as T & U[]
}
if (source instanceof Date) {
return new Date(source.getTime()) as T & Date
}
if (source && typeof source === 'object') {
return (Object.getOwnPropertyNames(source) as (keyof T)[]).reduce<T>((o, prop) => {
Object.defineProperty(o, prop, Object.getOwnPropertyDescriptor(source, prop)!)
o[prop] = deepCopy(source[prop])
return o
}, Object.create(Object.getPrototypeOf(source)))
}
return source
}
홀 오브젝트 콘텐츠의 단순한 클론에서는 단순히 인스턴스를 문자열화하고 해석합니다.
let cloneObject = JSON.parse(JSON.stringify(objectToClone))
objectToClone 트리의 데이터를 변경하는 동안 cloneObject는 변경되지 않습니다.그게 내 요구였다.
도움이 되었으면 좋겠다
나는 결국 다음과 같이 되었다.
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;
}
}
}
옵션 4에 대한 보충 @fenton, angular 사용JS는 다음 코드를 사용하여 객체 또는 어레이의 딥 복사를 수행하는 것이 비교적 간단합니다.
var deepCopy = angular.copy(objectOrArrayToBeCopied)
상세한 것에 대하여는, https://docs.angularjs.org/api/ng/function/angular.copy 를 참조해 주세요.
나는 클로닝을 할 때 다음을 사용한다.필요한 것은 대부분 처리하며 새로 만든 오브젝트에 기능도 복사합니다.
public static clone<T>(value: any) : T {
var o: any = <any>JSON.parse(JSON.stringify(value));
var functions = (<String[]>Object.getOwnPropertyNames(Object.getPrototypeOf(value))).filter(a => a != 'constructor');
for (var i = 0; i < functions.length; i++) {
var name = functions[i].toString();
o[name] = value[name];
}
return <T>o;
}
function instantiateEmptyObject(obj: object): object {
if (obj == null) { return {}; }
const prototype = Object.getPrototypeOf(obj);
if (!prototype) {
return {};
}
return Object.create(prototype);
}
function quickCopy(src: object, dest: object): object {
if (dest == null) { return dest; }
return { ...src, ...dest };
}
quickCopy(src, instantiateEmptyObject(new Customer()));
대상 개체가 이미 있으므로 새로 만들지 않으려면(배열을 업데이트하는 경우 등) 속성을 복사해야 합니다.
한 경우:
Object.keys(source).forEach((key) => {
copy[key] = source[key]
})
언급URL : https://stackoverflow.com/questions/28150967/typescript-cloning-object
'programing' 카테고리의 다른 글
JavaScript 또는 jQuery를 사용하여 새 탭에서 URL을 여는 방법 (0) | 2022.10.02 |
---|---|
MySQL에서 피벗 테이블 출력을 반환하려면 어떻게 해야 합니까? (0) | 2022.10.02 |
자바어로 "캐노컬 형식" 또는 "캐노컬 표현"이라는 용어는 무엇을 의미합니까? (0) | 2022.10.02 |
표의 모든 열을 나열하려면 어떻게 해야 합니까? (0) | 2022.10.02 |
외부 키 제약 조건에 사용된 열을 변경할 수 없습니다. (0) | 2022.10.02 |