bản thảo - đối tượng nhân bản


186

Tôi có một lớp siêu đó là phụ huynh ( Entity) cho nhiều lớp con ( Customer, Product, ProductCategory...)

Tôi đang tìm cách sao chép động một đối tượng có chứa các đối tượng phụ khác nhau trong Bản mô tả.

Ví dụ: a Customercó khác Productngười cóProductCategory

var cust:Customer  = new Customer ();

cust.name = "someName";
cust.products.push(new Product(someId1));
cust.products.push(new Product(someId2));

Để sao chép toàn bộ cây của đối tượng, tôi đã tạo một hàm trong 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;
}

Các newlỗi sau tăng khi được dịch sang javascript:error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.

Mặc dù kịch bản hoạt động, tôi muốn thoát khỏi lỗi được dịch mã

Câu trả lời:


255

Giải quyết vấn đề cụ thể

Bạn có thể sử dụng một xác nhận kiểu để nói với trình biên dịch mà bạn biết rõ hơn:

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;
}

Nhân bản

Hãy nhớ rằng đôi khi tốt hơn là viết bản đồ của riêng bạn - thay vì hoàn toàn năng động. Tuy nhiên, có một vài thủ thuật "nhân bản" mà bạn có thể sử dụng mang lại cho bạn hiệu ứng khác biệt.

Tôi sẽ sử dụng mã sau đây cho tất cả các ví dụ sau:

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'));

Cách 1: Lan truyền

Thuộc tính:
Phương thức: Không
Sao chép sâu: Không

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

Tùy chọn 2: Object.assign

Thuộc tính:
Phương thức: Không
Sao chép sâu: Không

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

Tùy chọn 3: Object.create

Thuộc tính: Kế thừa
Phương pháp: Kế thừa
Sâu Copy: Shallow thừa kế (thay đổi sâu sắc ảnh hưởng đến cả bản gốc và bản sao)

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

Tùy chọn 4: Chức năng sao chép sâu

Thuộc tính:
Phương thức: Không
Sao chép sâu:

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

Đóng, transpile ngừng khiếu nại với bản đánh máy 1.3, nhưng một khi trong javascript, nó sẽ bị lỗi. Bản đánh máy 1.4.1, sẽ không để nó đi.
David Laberge

1
Bạn sẽ hủy bỏ để làm rõ làm thế nào để bạn sử dụng chính xác này? Tôi đã đưa vào như một phương thức của đối tượng của mình và sau đó gặp lỗi nói rằng đó không phải là một chức năng ...
megalucio

1
Tôi nhận được lỗi sau: "ERROR TypeError: this.constructor (...) không phải là nhà xây dựng"
michali

3
Bạn vừa làm một ví dụ công khai từ khách hàng đó?
Blair Connolly

1
Ai đó có thể TL; DR cho tôi giải pháp nào được đưa ra trong tất cả các câu trả lời bảo tồn loại OO của bản sao cloned instanceof MyClass === truekhông?
Szczepan Hołyszewski

177

1. Sử dụng toán tử trải

const obj1 = { param: "value" };
const obj2 = { ...obj1 };

Toán tử lây lan lấy tất cả các trường từ obj1 và trải chúng trên obj2. Trong kết quả, bạn nhận được đối tượng mới với tham chiếu mới và các trường giống như trường ban đầu.

Hãy nhớ rằng đó là bản sao nông, có nghĩa là nếu đối tượng được lồng thì các tham số tổng hợp lồng nhau của nó sẽ tồn tại trong đối tượng mới bởi cùng một tham chiếu.

2.Object.assign ()

const obj1={ param: "value" };
const obj2:any = Object.assign({}, obj1);

Object.assign tạo bản sao thực, nhưng chỉ sở hữu các thuộc tính, vì vậy các thuộc tính trong nguyên mẫu sẽ không tồn tại trong đối tượng được sao chép. Nó cũng là bản sao nông.


3.Object.create ()

const obj1={ param: "value" };
const obj2:any = Object.create(obj1);

Object.create không thực hiện nhân bản thực sự , nó đang tạo đối tượng từ nguyên mẫu. Vì vậy, sử dụng nó nếu đối tượng nên sao chép các thuộc tính loại chính, bởi vì việc gán thuộc tính loại chính không được thực hiện bằng tham chiếu.

Điểm cộng của Object.create là mọi hàm được khai báo trong nguyên mẫu sẽ có sẵn trong đối tượng mới được tạo của chúng tôi.


Vài điều về bản sao nông

Bản sao nông đưa vào đối tượng mới tất cả các trường của đối tượng cũ, nhưng điều đó cũng có nghĩa là nếu đối tượng ban đầu có các trường kiểu hỗn hợp (đối tượng, mảng, v.v.) thì các trường đó được đặt trong đối tượng mới có cùng tham chiếu. Trường đột biến như vậy trong đối tượng ban đầu sẽ được phản ánh trong đối tượng mới.

Nó có thể trông giống như một cạm bẫy, nhưng thực sự tình huống khi toàn bộ đối tượng phức tạp cần được sao chép là rất hiếm. Bản sao nông sẽ sử dụng lại hầu hết bộ nhớ, điều đó có nghĩa là rất rẻ so với bản sao sâu.


Bản sao sâu

Toán tử lây lan có thể được tiện dụng để sao chép sâu.

const obj1 = { param: "value", complex: { name: "John"}}
const obj2 = { ...obj1, complex: {...obj1.complex}};

Trên mã đã tạo bản sao sâu của obj1. Trường tổng hợp "phức tạp" cũng được sao chép vào obj2. Trường đột biến "phức tạp" sẽ không phản ánh bản sao.


8
Tôi không nghĩ điều đó hoàn toàn chính xác. Object.create(obj1)tạo một đối tượng mới và gán obj1 làm nguyên mẫu. Không có trường nào trong obj1 được sao chép hoặc nhân bản. Vì vậy, những thay đổi trên obj1 mà không sửa đổi obj2 sẽ được nhìn thấy, vì về cơ bản nó không có thuộc tính. Nếu bạn sửa đổi obj2 trước, nguyên mẫu sẽ không được nhìn thấy cho trường bạn xác định do trường obj2 có tên gần hơn trong cấu trúc phân cấp.
Ken Rimple

3
Thay vào đó, bạn cũng sẽ thấy ES2015 và các nhà phát triển bản thảo thực hiện việc này, điều này tạo ra một đối tượng từ tham số thứ nhất (trong trường hợp của tôi là một tham số trống) và sao chép các thuộc tính từ các tham số thứ hai và tiếp theo): let b = Object.assign({}, a);
Ken Rimple

@KenRimple Bạn đúng 100%, tôi đã thêm một số thông tin.
Maciej Sikora


5
Object.assign sẽ tạo ra các vấn đề cho các đối tượng sâu. Ví dụ: {name: 'x', các giá trị: ['a', 'b', 'c']}. Sau khi sử dụng Object.assign để sao chép, cả hai đối tượng đều chia sẻ mảng giá trị để cập nhật cái này ảnh hưởng đến cái kia. Xem: developer.mozilla.org/en/docs/Web/JavaScript/Reference/ Khăn (phần 'Cảnh báo cho bản sao sâu'). Nó nói: Để nhân bản sâu, chúng ta cần sử dụng các lựa chọn thay thế khác. Điều này là do Object.assign () sao chép tham chiếu thuộc tính khi thuộc tính được gán là một đối tượng.
Meir

47

Thử cái này:

let copy = (JSON.parse(JSON.stringify(objectToCopy)));

Đó là một giải pháp tốt cho đến khi bạn đang sử dụng các đối tượng rất lớn hoặc đối tượng của bạn có các thuộc tính không thể xác định được.

Để bảo vệ an toàn loại, bạn có thể sử dụng chức năng sao chép trong lớp bạn muốn tạo bản sao từ:

getCopy(): YourClassName{
    return (JSON.parse(JSON.stringify(this)));
}

hoặc theo cách tĩnh:

static createCopy(objectToCopy: YourClassName): YourClassName{
    return (JSON.parse(JSON.stringify(objectToCopy)));
}

5
Điều này là ổn, nhưng bạn nên nhớ rằng bạn sẽ mất thông tin nguyên mẫu và tất cả các loại không được hỗ trợ trong json khi nối tiếp / phân tích cú pháp.
Stanislav E. Govorov

1
Ngoài ra, điều này có vẻ kém hiệu quả hơn so với chức năng deepCopy được cung cấp ở trên .
Mojtaba

Tôi gặp lỗi này: "Chuyển đổi cấu trúc vòng tròn thành JSON" khi tôi sử dụng "(JSON.parse (JSON.opesify (objectToCopy)));"
Cedric Arnould

Chỉ hoạt động trong 98% các trường hợp. Có thể dẫn đến thiếu khóa với undefinedgiá trị, ít nhất. nếu objectToCopy = { x : undefined};sau khi chạy mã của bạn Object.keys(objectToCopy).length1, trong khi Object.keys(copy).length0.
Aidin

33

TypeScript / JavaScript có toán tử riêng để nhân bản nông:

let shallowClone = { ...original };

15

Thật dễ dàng để có được một bản sao nông với "Đối tượng trải rộng" được giới thiệu trong TypeScript 2.1

TypeScript này: let copy = { ...original };

tạo JavaScript này:

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


2
Lưu ý: điều này sẽ tạo ra một bản sao nông
Jimmy Kane

11

Đối với bản sao sâu nối tiếp, với Thông tin loại là,

export function clone<T>(a: T): T {
  return JSON.parse(JSON.stringify(a));
}

1
Điều này có thể thay đổi thứ tự của các đạo cụ. Chỉ là một cảnh báo cho một số người. Ngoài ra nó không xử lý ngày đúng.
Pangamma

Điều này có thể thay đổi thứ tự của các đạo cụ - có thể thử npmjs.com/package/es6-json-urdy-opesify thay vìJSON.stringify
Polv

@Polv, nếu ai đó đang dựa vào thứ tự của các khóa trong một đối tượng, tôi nghĩ họ có vấn đề lớn hơn clone. :)
Aidin

Giải pháp này có thể bỏ lỡ các khóa có undefinedgiá trị. Xem nhận xét của tôi về câu trả lời tương tự ở trên: stackoverflow.com/questions/28150967/typescript-claming-object/iêu
Aidin

7

Tôi đảm nhận nó:

Object.assign(...) chỉ sao chép các thuộc tính và chúng tôi mất nguyên mẫu và phương thức.

Object.create(...) không sao chép các thuộc tính cho tôi và chỉ tạo một nguyên mẫu.

Điều làm việc cho tôi là tạo một nguyên mẫu bằng cách sử dụng Object.create(...)và sao chép các thuộc tính vào nó bằng cách sử dụng Object.assign(...):

Vì vậy, đối với một đối tượng foo, tạo bản sao như thế này:

Object.assign(Object.create(foo), foo)

Có một điều rất tinh tế đang diễn ra ở đây. Bạn đang thực sự trở thành foocha mẹ nguyên mẫu của clonedFoo(đối tượng mới). Mặc dù điều này nghe có vẻ ổn, nhưng bạn nên nhớ rằng một tài sản bị thiếu sẽ được tra cứu trong chuỗi nguyên mẫu, vì vậy hãy const a = { x: 8 }; const c = Object.assign(Object.create(a), a); delete c.x; console.log(c.x);in ra 8, trong khi nên undefined! (Liên kết REPL: repl.it/repls/CompetitivePreeemiveKeygen )
Aidin

Ngoài ra, nếu sau này bạn thêm một thuộc tính vào foo, nó sẽ tự động hiển thị cho clonedFoo! ví dụ foo.y = 9; console.log(clonedFoo.y)sẽ in ra 9thay vì undefined. Rất có khả năng đó không phải là những gì bạn đang yêu cầu!
Aidin

@Aidin Vậy làm thế nào để đảm bảo một bản sao sâu?
Muhammad Ali

bất kỳ giải pháp nào khác trong câu hỏi này, đang thực hiện đệ quy theo giá trị sao chép (ví dụ stackoverflow.com/a/53025968 bởi marckassay) đảm bảo rằng, vì không có tham chiếu đến đối tượng nguồn được duy trì trong đối tượng đích.
Aidin

5

Bạn cũng có thể có một cái gì đó như thế này:

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;
    }
}

Chỉ cần đảm bảo rằng bạn ghi đè clonephương thức trong tất cả các Entitylớp con nếu không bạn sẽ kết thúc bằng bản sao một phần.

Kiểu trả về thissẽ luôn khớp với kiểu của thể hiện.


4

Thêm "lodash.clonedeep": "^4.5.0"vào của bạn package.json. Sau đó sử dụng như thế này:

import * as _ from 'lodash';

...

const copy = _.cloneDeep(original)

3

Nếu bạn gặp lỗi này:

TypeError: this.constructor(...) is not a function

Đây là kịch bản chính xác:

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;
}

4
Có đúng cloneObj[attribut] = this.clone();không? hoặc ý bạn làcloneObj[attribut] = this[attribut].clone();
Serginho

2

Tự mình giải quyết vấn đề này và cuối cùng đã viết một thư viện nhỏ clonizable-ts cung cấp một lớp trừu tượng, bổ sung một phương thức nhân bản cho bất kỳ lớp nào mở rộng nó. Lớp trừu tượng mượn Hàm Deep Copy được mô tả trong câu trả lời được chấp nhận bởi Fenton chỉ thay thế copy = {};bằng copy = Object.create(originalObj)để bảo toàn lớp của đối tượng ban đầu. Dưới đây là một ví dụ về việc sử dụng lớp.

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

Hoặc bạn chỉ có thể sử dụng Cloneable.clonephương thức trợ giúp:

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    

2

Đây là bản mash-up của tôi! Và đây là một liên kết StackBlitz với nó. Tôi hiện chỉ giới hạn ở việc sao chép các loại đối tượng và loại đối tượng đơn giản nhưng tôi có thể sửa đổi dễ dàng.

   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;
    };

1
Hoạt động khá tốt như xa như tôi có thể thấy. Tuy nhiên, typeof nullcũng là một đối tượng, vì vậy truy vấn nên được if (source[P] !== null && typeof source[P] === 'object')thay thế. Nếu không, giá trị null của bạn sẽ bị biến thành một đối tượng trống.
MortenMoulder

1

Do TypeScript 3.7 được phát hành, các bí danh loại đệ quy hiện được hỗ trợ và nó cho phép chúng ta xác định một loại deepCopy()chức năng an toàn :

// 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

Sân chơi


0

Đối với một bản sao đơn giản của nội dung của đối tượng lỗ, tôi chỉ cần xâu chuỗi và phân tích ví dụ:

let cloneObject = JSON.parse(JSON.stringify(objectToClone))

Trong khi tôi thay đổi dữ liệu trong cây objectToClone, không có thay đổi nào trong cloneObject. Đó là yêu cầu của tôi.

Hy vọng nó sẽ giúp


1
Có thể bỏ lỡ các khóa có undefinedgiá trị. Xem nhận xét của tôi về câu trả lời tương tự ở trên: stackoverflow.com/questions/28150967/typescript-claming-object/iêu
Aidin

0

Tôi đã kết thúc việc làm:

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;
}

Bởi vì:

var cloneObj = new (<any>this.constructor());

từ @Fenton đã đưa ra lỗi thời gian chạy.

Phiên bản bản in: 2.4.2


0

Làm thế nào về jQuery cũ tốt?! Đây là bản sao sâu sắc:

var clone = $.extend(true, {}, sourceObject);

Câu hỏi này không được gắn thẻ JQuery cũng như JQuery không được đề cập trong câu hỏi. Nó cũng sẽ là chi phí khổng lồ để đưa JQuery vào một dự án chỉ để thực hiện một bản sao sâu.
LewisM

Điều đó đủ công bằng, nhưng OP không phải là về cách sao chép, mà là về việc xác định một vấn đề trong mã mà anh ta cung cấp và bạn đã trả lời bằng cách nhân bản jQuery mà không thực sự trả lời câu hỏi. Tôi không phải là người đánh giá thấp bạn, nhưng tôi tin rằng đó có thể là lý do khiến bạn bị hạ thấp.
LewisM

0

Tôi đã cố gắng tạo ra một dịch vụ sao chép / sao chép chung giữ lại các loại cho các đối tượng lồng nhau. Rất thích phản hồi nếu tôi làm điều gì đó sai, nhưng nó dường như hoạt động cho đến nay ...

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;
    }
  }
}

0

Trong typeScript tôi kiểm tra với góc, và nó hoạt động tốt

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.");
    }

0

Để nhân bản sâu một đối tượng có thể chứa các đối tượng khác, mảng và vv tôi sử dụng:

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
}

Sử dụng:

const obj = {a: [1,2], b: 's', c: () => { return 'h'; }, d: null, e: {a:['x'] }}
const objClone = clone(obj)

0

Bạn có thể sử dụng phép gán hủy với cú pháp lây lan :

var obj = {id = 1, name = 'product1'};
var clonedObject = {...obj};

1
Mặc dù mã này có thể trả lời câu hỏi, việc cung cấp ngữ cảnh bổ sung về cách thức và / hoặc lý do giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
leopal

-2

Nếu bạn đã có đối tượng đích, vì vậy bạn không muốn tạo lại nó (như nếu cập nhật một mảng), bạn phải sao chép các thuộc tính.
Nếu đã làm theo cách này:

Object.keys(source).forEach((key) => {
    copy[key] = source[key]
})

Khen ngợi là do. (nhìn vào tiêu đề "phiên bản 2")


Chức năng? Mảng nào? Đối tượng ngày? Bảo quản các loại? Và tất nhiên những gì về các đối tượng? Nếu chức năng trên gặp phải bất kỳ loại nào ở trên, nó sẽ không thể sao chép sâu. Bạn sẽ sao chép các tài liệu tham khảo vào cùng một dữ liệu. Khi họ đi chỉnh sửa các thuộc tính con của đối tượng nhân bản, cuối cùng họ cũng sẽ chỉnh sửa đối tượng gốc.
Pangamma
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.