我有一个超类,它是许多子类(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'。

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


当前回答

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

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

其他回答

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

对于一个简单的克隆的hole对象的内容,我简单地stringify和解析实例:

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

当我在objectToClone树中更改数据时,在cloneObject中没有更改。这就是我的要求。

希望能有所帮助

下面是deepCopy在TypeScript中的实现(代码中不包含任何内容):

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
}

我在克隆时使用以下方法。它处理我需要的几乎所有东西,甚至将函数复制到新创建的对象。

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

TypeScript/JavaScript有自己的浅克隆操作符:

let shallowClone = { ...original };