克隆 TypeScript 对象

14

我有一个 TypeScript 类

export class Restaurant {

  constructor ( private id: string, private name: string ) {

  }

  public getId() : string {
    return this.id;
  }

  public setId(_id : string) {
    this.id = _id;
  }

  public getName () {
    return this.name;
  }

  public setName ( _name:string ) {
    this.name = _name;
  }

}

我随后创建了该类的一个实例(这是一个示例):

restaurant:Restaurant = new Restaurant(1,"TestRest");

然后我将这个餐厅对象存储在某种缓存中

cache.store( restaurant );

然后在我的应用程序中稍后获取餐馆

var restToEdit = cache.get( "1" );
restToEdit.setName( "NewName" );

但由于 JavaScript 对象的按引用传递,在 restToEdit 中所做的更改也会保存在缓存中的餐厅中。

我希望缓存中的餐厅是一个完全不同的实例,而不是与 restToEdit 相同的实例。

我尝试过使用 jQuery.clone 和 extend,但似乎并没有起作用,我认为这是因为它是一个 TypeScript 对象。或者这无关紧要吗?

如果有关于如何克隆此对象的任何答案将不胜感激。

谢谢

4个回答

20
  • Using standard ES6 features

    const clone = Object.assign({}, myObject)
    

    Warning: this performs a shallow clone.

    This excellent page from MDN contains tons of details on cloning, including a polyfill for ES5

  • A "quick" way of deep cloning is to use JSON utilities

    const clone = JSON.parse(JSON.stringify(myObject))
    
  • A "proper" way of cloning is to implement a clone method or a copy constructor...

我知道,我知道,不够的JQuery


2
Object.assign 会使用引用进行复制。 - Thaadikkaaran
3
使用Json.parse然后Json.stringify会丢失分配给对象的函数。 - mwild
@JaganathanBantheswaran... 如果你只是浅克隆或克隆不可变属性,那就完全没问题! - Bruno Grieder
在 TypeScript 中使用 Object.assign 感觉不太对。显然,我知道一旦编译成 js 就没问题了,但这似乎不是我的解决方案,而且即使如此,我也想要一个深度克隆,正如我所解释的,这些属性并不是不可变的。 - mwild
1
@JaganathanBantheswaran angular.copy在Angular 2中不可用。 - mwild
显示剩余3条评论

5

这对我来说似乎可行:

var newObject = Object.assign(Object.create(oldObj), oldObj)

Object.create创建一个新实例并具有空属性。 然后,Object.assign将该新实例分配给属性。

克隆函数的更健壮版本。

    clone(obj) {
        if(Array.isArray(obj)) {
            return Array.from(obj);
        } else {
            return Object.assign(Object.create(obj), obj);
        }
    }

2
仅进行浅克隆。任何引用仍然指向原始对象。 - etech
我建议使用 Object.create(Object.getPrototypeOf(obj)) 替代 Object.create(obj)。当前代码存在以下问题:如果在复制过程中,obj 有一个属性的值为 undefined,那么在原始 obj 中更改此属性的值后,克隆对象将会看到这个变化。 - user3707125

3
如果您正在使用TS 2.1,您可以使用对象展开运算符来创建浅拷贝:
const obj = { a: 1 };
const clonedObj = { ...obj };

1

.clone() 只能克隆DOM元素。如果要克隆JavaScript对象,请尝试使用 jQuery.extend。像这样

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

Typescript会被转译成JavaScript,因此,JavaScript的方式可以正常工作。
演示:

// Transpiled version of TypeScript
"use strict";
    var Restaurant = (function () {
        function Restaurant(id, name) {
            this.id = id;
            this.name = name;
        }
        Restaurant.prototype.getId = function () {
            return this.id;
        };
        Restaurant.prototype.setId = function (_id) {
            this.id = _id;
        };
        Restaurant.prototype.getName = function () {
            return this.name;
        };
        Restaurant.prototype.setName = function (_name) {
            this.name = _name;
        };
        return Restaurant;
    }());

// Test Snippet
var r1 = new Restaurant(1, "A");
var r2 = jQuery.extend(true, {}, r1);

r2.setName("B");

console.log(r1.name);
console.log(r2.name);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


谢谢,这个方案可行。只是在 TypeScript 方面感觉不太对劲。我不喜欢在 TypeScript 中使用 JavaScript 代码,仅仅因为我知道它会工作。但现在看来这似乎是唯一的解决方案。谢谢。 - mwild
你可以在类/原型上进行封装:public clone(): Restaurant { /* 相同的 jQuery 代码,只需返回 r2 */ } - chrisbajorin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接