在 TypeScript 中克隆物件

Shuvayan Ghosh Dastidar 2023年1月30日
  1. TypeScript 中的克隆機制
  2. 在 TypeScript 中使用 Spread 運算子克隆物件
  3. 在 TypeScript 中使用 Object.assign() 方法克隆物件
  4. TypeScript 中巢狀物件的深度複製
  5. TypeScript 中類的深拷貝
在 TypeScript 中克隆物件

在實現某些服務時,克隆物件是一件很常見的事情。克隆是指建立現有物件的副本,包括其欄位。

可能會使用物件克隆的一些用例是在函式中返回物件的副本。

在更改某些屬性後更改其某些屬性或在 React 的情況下使用 setState。本文演示了 TypeScript 中不同型別的克隆機制以及如何實現它們。

TypeScript 中的克隆機制

大致有兩種克隆機制——淺拷貝深拷貝。顧名思義,淺拷貝複製物件內的屬性和引用巢狀屬性。

同時,在深拷貝的情況下,它的所有屬性都被複制,複製或克隆物件的任何變化都不會影響原始物件。下面的程式碼段將討論淺拷貝和深拷貝是如何工作的。

let a : number = 5;
let b = a;
b = 6;
//does not hold reference to previous original variable and thus is deep copied
console.log(b);
console.log(a);

type Person = {
    name : string;
    age : number;
}
var person : Person = {
    name : 'Geralt',
    age : 95
}
// shallow copy
var personCopy : Person = person;
personCopy.age = 90;
console.log(personCopy.age)
console.log(person.age)

輸出:

6
5
90
90

因此,隱式只為物件分配淺表副本,因為複製物件中的任何更改都會影響從中複製它的原始物件。

在 TypeScript 中使用 Spread 運算子克隆物件

spread 運算子是 JavaScript ES6 版本中可用功能的新增功能,可以有效地複製物件。考慮前面程式碼段中的示例。

type Person = {
    name : string;
    age : number;
}
var person : Person = {
    name : 'Geralt',
    age : 95
}
var personCopy : Person = { ...person};
personCopy.age = 90;
console.log(personCopy.age)
console.log(person.age)

輸出:

90
95

因此,spread 運算子可以製作物件的深層副本。但是,在巢狀物件的情況下它會失敗。

在 TypeScript 中使用 Object.assign() 方法克隆物件

Object.assign() 的工作方式與擴充套件運算子的情況類似,可用於克隆簡單物件,但在巢狀物件的情況下會失敗。

var personCopy : Person = Object.assign({}, person);

TypeScript 中巢狀物件的深度複製

必須遞迴複製每個元素以複製巢狀物件。對於陣列,擴充套件運算子適用於原始資料型別。

但是,必須為物件陣列單獨複製每個元素。我們可以設計一個函式來實現這一點;

function deepCopy<T>(instance : T) : T {
    if ( instance == null){
        return instance;
    }

    // handle Dates
    if (instance instanceof Date) {
        return new Date(instance.getTime()) as any;
    }

    // handle Array types
    if (instance instanceof Array){
        var cloneArr = [] as any[];
        (instance as any[]).forEach((value)  => {cloneArr.push(value)});
        // for nested objects
        return cloneArr.map((value: any) => deepCopy<any>(value)) as any;
    }
    // handle objects
    if (instance instanceof Object) {
        var copyInstance = { ...(instance as { [key: string]: any }
        ) } as { [key: string]: any };
        for (var attr in instance) {
            if ( (instance as Object).hasOwnProperty(attr)) 
                copyInstance[attr] = deepCopy<any>(instance[attr]);
        }
        return copyInstance as T;
    }
    // handling primitive data types
    return instance;
}
type info = {
    gender : 'male' | 'female';
}

type Person = {
    name : string;
    age : number;
    info : info;
}
var person : Person = {
    name : 'Geralt',
    age : 95,
    info : {
        gender : "male"
    }
}

var personCopy : Person = deepCopy<Person>(person);
console.log(personCopy);

personCopy.info.gender = "female";
console.log(person.info.gender);
console.log(personCopy,info.gender);

輸出:

male
female

因此,成功的深層複製是為巢狀物件完成的。

TypeScript 中類的深拷貝

可以使用自定義函式複製類,並在該函式中建立一個新例項。這使作者可以完全控制複製功能。

class Witcher{
    name : string;
    age : number;
    constructor() {
        this.name = "Geralt"
        this.age  = 43;
    }
    greet(){
        return "Hi I am witcher known as " + this.name
    }

    copy(){
        var witcherIns = new Witcher();
        witcherIns.name = this.name;
        witcherIns.age = this.age;
        return witcherIns;
    }
}

var witcherObj = new Witcher();
var witcherObjCopy = witcherObj.copy();
console.log(witcherObjCopy);
console.log(witcherObjCopy.greet());

輸出:

Witcher: {
  "name": "Geralt",
  "age": 43
} 
"Hi I am witcher known as Geralt" 
Shuvayan Ghosh Dastidar avatar Shuvayan Ghosh Dastidar avatar

Shuvayan is a professional software developer with an avid interest in all kinds of technology and programming languages. He loves all kinds of problem solving and writing about his experiences.

LinkedIn Website

相關文章 - TypeScript Object