类型错误:使用私有字段/方法两次初始化对象是错误的
当通过类构造函数创建的对象再次经历类构造并且该类包含 私有属性 时,会发生 JavaScript 异常 "使用私有字段/方法两次初始化对象是错误的"。这通常是由 返回覆盖 技巧引起的。
¥The JavaScript exception "Initializing an object twice is an error with private fields/methods" occurs when an object that was created via a class constructor goes through the class construction again, and the class contains a private property. This is usually caused by the return override trick.
信息
¥Message
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)
错误类型
什么地方出了错?
¥What went wrong?
对于任何对象,如果它已经包含私有字段或方法,则再次安装相同字段将是一个错误。在调用类构造函数时,私有属性会安装在 this
的值上,因此如果 this
值是该类的已构造实例,则可能会发生此错误。
¥For any object, if it already contains a private field or method, it would be an error to install the same field again. Private properties are installed on the value of this
when the class constructor is called, so this error could happen if the this
value is an already-constructed instance of this class.
通常,构造函数中的 this
是一个新创建的对象,它没有任何预先存在的属性。但是,它可以被基类的返回值覆盖。如果基类返回另一个对象,该对象将替换当前对象作为 this
的值:
¥Usually, this
in a constructor is a newly created object which doesn't have any preexisting properties. However, it can be overridden by the return value of the base class. If the base class returns another object, that object would replace the current object as the value of this
:
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
的实例,则将使用 anyObject
作为 this
值来调用 Derived
构造函数,因此在 anyObject
上安装 #x
私有字段。这是 "返回覆盖" 技巧,它允许你定义不相关对象的任意信息。但是,如果你调用 new Derived(new Derived())
,或再次调用 new Derived(anyObject)
,Derived
构造函数将尝试在已经具有 #x
私有字段的对象上再次安装 #x
私有字段,从而导致此错误。
¥If you call new Derived(anyObject)
, where anyObject
is not an instance of Derived
, the Derived
constructor will be called with anyObject
as the this
value, and therefore install the #x
private field on anyObject
. This is the "return override" trick, which allows you to define arbitrary information on unrelated objects. However, if you call new Derived(new Derived())
, or call new Derived(anyObject)
again, the Derived
constructor will try to install the #x
private field again on an object which already has the #x
private field, causing this error.