TypeError: 私有字段/方法中两次初始化对象是一个错误

当通过类构造函数创建的对象再次经历类构造,并且类包含私有属性时,会发生 JavaScript 异常“初始化对象两次是使用私有字段/方法的错误”。这通常是由返回值覆盖技巧引起的。

消息

TypeError: Cannot initialize #x twice on the same object (V8-based)
TypeError: Initializing an object twice is an error with private fields (Firefox)
TypeError: Cannot redefine existing private field (evaluating 'super(o)') (Safari)

TypeError: Cannot initialize private methods of class X twice on the same object (V8-based)
TypeError: Initializing an object twice is an error with private methods (Firefox)
TypeError: Cannot install same private methods on object more than once (evaluating 'super(o)') (Safari)

错误类型

哪里出错了?

对于任何对象,如果它已经包含私有字段或方法,则再次安装相同的字段将是错误的。当调用类构造函数时,私有属性会安装在 this 的值上,因此如果 this 值是该类的已构造实例,则可能会发生此错误。

通常,构造函数中的 this 是一个新创建的对象,它没有任何预先存在的属性。但是,它可以被基类的返回值覆盖。如果基类返回另一个对象,则该对象将替换当前对象作为 this 的值

js
class Base {
  constructor(o) {
    // This object will become the this value of any subclass
    return o;
  }
}

class Derived extends Base {
  #x = 0;
}

如果调用 new Derived(anyObject),其中 anyObject 不是 Derived 的实例,则 Derived 构造函数将以 anyObject 作为 this 值被调用,因此将在 anyObject 上安装 #x 私有字段。这是“返回值覆盖”技巧,它允许您在不相关对象上定义任意信息。但是,如果再次调用 new Derived(new Derived()) 或调用 new Derived(anyObject),则 Derived 构造函数将尝试在已具有 #x 私有字段的对象上再次安装 #x 私有字段,从而导致此错误。

另请参阅