繁体   English   中英

在 javascript / typescript 中复制类的实例

[英]copy instance of class in javascript / typescript

我有两个对象 inst1、inst2,它们都是同一类的实例。 如果我使用

inst2 = JSON.parse(JSON.stringify(inst1));

现在,如果我更改 inst2 的属性值,inst1 中的值不会改变。 太棒了。 但遗憾的是 inst2 的方法已经消失了。 所以如果我这样做

inst2.method1();

我收到错误消息“inst2.method1 不是一个函数”

有什么方法可以在不破坏方法的情况下复制实例中的值吗? (显然我可以费力地复制每个值。我试图避免这种情况,因为我很懒。)

我试图遵循打字稿 - 克隆对象,但我无法使其工作 -

好的,我玩了一点,因为提供的答案不是 100% 清楚。 如果你想有一个浅拷贝并复制方法,你可以使用Object.create

再次重申:如果您的对象足够简单,那么Object.create就足够了

const originalPerson = new Person("John");
originalPerson.address = new Address("Paris", "France");


const newPerson = Object.create(originalPerson);

/// this will be true
const isInstanceOf = newPerson instanceof Person;

//this will change the property of the new person ONLY
newPerson.name = "Peter";

//methods will work
newPerson.someMethod();

//methods will work even on nested objects instances
newPerson.address.anotherMethod();

// BUT if we change the city on any of the instances -  will change the address.city of both persons since we have done a shallow copy
newPerson.address.city = "Berlin";

我已经创建了 typescript 游乐场(只需删除类型)来展示它的工作原理以及它的使用缺点 -链接到游乐场

另一种方法是类本身具有克隆方法并负责其自身的克隆逻辑。 下面是一个示例,以及指向另一个游乐场的链接

class Address {
  constructor(city, country) {
    this.city = city;
    this.country = country;
  }

  clone() {
    // no special logic, BUT if the address eveolves this is the place to change the clone behvaiour
    return Object.create(this);
  }

  getAddressDetails() {
    return `City: ${this.city} country ${this.country}`;
  }
}

class Person {
  constructor(name, address) {
    this.name = name;
    this.address = address;
  }

  clone() {
    const newInstance = Object.create(this);
    //clone all other class instances
    newInstance.address = this.address.clone();
    return newInstance;
  }

  getPersonDetails() {
    //calling internally address.getAddressDetails() ensures that the inner object methods are also cloned
    return `This is ${this.name}, I live in ${this.address.getAddressDetails()}`
  }
}

const originalAddress = new Address("Paris", "France");
const originalPerson = new Person("John", originalAddress);

const clonedPerson = originalPerson.clone();
clonedPerson.name = "Peter";
clonedPerson.address.city = "Berlin";
clonedPerson.address.country = "Germany";

// Log to console
console.log(`Original person: ${originalPerson.getPersonDetails()}`)
console.log(`Cloned person: ${clonedPerson.getPersonDetails()}`)

您应该使用结构化克隆,请参阅以下答案: How do I correctly clone a JavaScript object?

您当前的代码不起作用的原因是因为您正在解析一个字符串化的 json 对象。 Json stringify 将删除对象的所有方法,只将对象值字符串化。

我在方便的时候回到了这一点,并通过结合上述一些答案取得了相当大的进步。 当我意识到不可能编写通用克隆器时,通用克隆器变得非常丑陋(见下文)并且仍然无法工作(对于类对象数组)。

我使用术语类对象来表示由类定义的对象。

如果一个类对象包含一个本身是类对象类型的变量,称它为 subObj,那么通用克隆器无法知道 1) 它应该复制 subObj 还是 2) 它应该创建一个新的 subObj 实例并复制到子对象中-特性。 答案取决于课堂上的意义。

在 subObj 上面的第一种情况下。 只是指向 subObj 的另一个实例的指针。

因此,我非常同意 Svetoslav Petkov 回答的第二部分,即“类本身[应该]有一个克隆方法并负责它自己的克隆逻辑。”。

对于它的价值,这是就我使用通用克隆器(在 TypeScript 中)获得的而言。 它改编自其他答案并自由地创建类对象的新实例:

public clone(): any {
var cloneObj = new (this.constructor as any)() as any;
for (var attribut in this) {
  // attribut is a string which will take the values of the names of the propertirs in 'this'
  // And for example, if aNumber is a property of 'this' then
  // this['aNumber'] is the same as this.aNumber
  if (typeof this[attribut] === "object") {
    let thisAttr = this[attribut] as any;
    let cloneAttr = cloneObj[attribut] as any;
    if (this[attribut] instanceof Array) {
      for (let i in thisAttr) {
        cloneAttr[i] = thisAttr[i];         // **** will not work on arrays of objects!!
      }
      continue; // to next attrib in this
    }
    if (this[attribut] instanceof Date) {
      cloneAttr.setTime(thisAttr.getTime());
      continue; // to next attrib in this
    }
    try {
      cloneObj[attribut] = thisAttr.clone();
      //cloneObj[attribut] = this.clone();     // with this, (from https://stackoverflow.com/questions/28150967/typescript-cloning-object) stack just gets bigger until overflow
    }
    catch (err) {
      alert("Error: Object " + attribut + " does not have clone method." +
        "\nOr " + err.message);
    }
  } else {
    cloneObj[attribut] = this[attribut];
  }
}
return cloneObj;

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM