TypeError: Initializing an object twice is an error with private fields/methods

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)

錯誤型別

TypeError

哪裡出錯了?

對於任何物件,如果它已經包含一個私有欄位或方法,那麼再次安裝相同的欄位將是一個錯誤。私有元素在呼叫類建構函式時安裝在 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 私有欄位,從而導致此錯誤。

另見