我有一个超类,它是许多子类(Customer, Product, ProductCategory…)的父类(Entity)。

我想在Typescript中动态克隆一个包含不同子对象的对象。

例如:拥有不同产品的客户拥有一个ProductCategory

var cust:Customer  = new Customer ();

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

为了克隆对象的整个树,我在实体中创建了一个函数

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时,将引发以下错误:错误TS2351:不能对缺少调用或构造签名的表达式使用'new'。

虽然脚本工作,但我想摆脱转译错误


当前回答

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

其他回答

下面是一个现代的实现,它也解释了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}

jQuery怎么样?!下面是深度克隆:

var clone = $.extend(true, {}, sourceObject);
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()));

使用扩展运算符… Const obj1 ={参数:"value"}; Const obj2 ={…其中obj1};

展开运算符将obj1中的所有字段展开到obj2上。在结果中,您将获得具有新引用的新对象和与原始对象相同的字段。

记住,这是浅复制,这意味着如果对象是嵌套的,那么它的嵌套复合参数将通过相同的引用存在于新对象中。

Object.assign () Const obj1={参数:"value"}; const obj2:any =对象。分配({},其中obj1);

对象。赋值创建真实的副本,但只有自己的属性,因此原型中的属性将不存在于被复制的对象中。这也是浅拷贝。


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

对象。Create不是做真正的克隆,它是从原型创建对象。因此,如果对象应该克隆主类型属性,请使用它,因为主类型属性的赋值不是通过引用完成的。

对象的优点。Create是指在prototype中声明的任何函数都可以在我们新创建的对象中使用。


关于浅复制的一些事情

浅拷贝将旧对象的所有字段放入新对象中,但这也意味着如果原始对象具有复合类型字段(对象,数组等),那么这些字段将放入具有相同引用的新对象中。原物体中这种磁场的突变会在新物体中反映出来。

这可能看起来像一个陷阱,但真正需要复制整个复杂对象的情况是罕见的。浅拷贝将重用大部分内存,这意味着与深拷贝相比非常便宜。


深拷贝

展开运算符可以方便地进行深度复制。

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

上面的代码创建了obj1的深度拷贝。复合字段“complex”也被复制到obj2中。突变字段“复杂”不会反映副本。

如果你已经有了目标对象,所以你不想重新创建它(就像更新一个数组一样),你必须复制属性。 如果这样做:

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

赞美是应得的。(请看标题“版本2”)