super

Baseline 已廣泛支援

此特性已經非常成熟,並且適用於許多裝置和瀏覽器版本。自 2016 年 3 月以來,它已在所有瀏覽器中可用。

super 關鍵字用於訪問物件字面量或類的 [[Prototype]] 上的屬性,或者呼叫超類的建構函式。

super.propsuper[expr] 表示式在類和物件字面量中的任何方法定義中都是有效的。super(...args) 表示式在類建構函式中是有效的。

試一試

class Foo {
  constructor(name) {
    this.name = name;
  }

  getNameSeparator() {
    return "-";
  }
}

class FooBar extends Foo {
  constructor(name, index) {
    super(name);
    this.index = index;
  }

  // Does not get called
  getNameSeparator() {
    return "/";
  }

  getFullName() {
    return this.name + super.getNameSeparator() + this.index;
  }
}

const firstFooBar = new FooBar("foo", 1);

console.log(firstFooBar.name);
// Expected output: "foo"

console.log(firstFooBar.getFullName());
// Expected output: "foo-1"

語法

js
super()
super(arg1)
super(arg1, arg2)
super(arg1, arg2, /* …, */ argN)

super.propertyOnParent
super[expression]

描述

super 關鍵字可以透過兩種方式使用:“函式呼叫”(super(...args)),或“屬性查詢”(super.propsuper[expr])。

注意:super 是一個關鍵字,這些是特殊的語法結構。super 不是指向原型物件的變數。嘗試讀取 super 本身會丟擲 SyntaxError

js
const child = {
  myParent() {
    console.log(super); // SyntaxError: 'super' keyword unexpected here
  },
};

在派生類(使用 extends)的建構函式體中,super 關鍵字可以作為“函式呼叫”(super(...args))出現,它必須在 this 關鍵字使用之前,並且在建構函式返回之前呼叫。它呼叫父類的建構函式並繫結父類的公共欄位,之後派生類的建構函式可以進一步訪問和修改 this

“屬性查詢”形式可用於訪問物件字面量或類的 [[Prototype]] 的方法和屬性。在類的主體中,super 的引用可以是超類的建構函式本身,也可以是建構函式的 prototype,具體取決於執行上下文是例項建立還是類初始化。更多詳細資訊請參見示例部分。

請注意,super 的引用由宣告 super 的類或物件字面量決定,而不是由呼叫方法的物件決定。因此,解綁或重新繫結方法不會改變其中 super 的引用(儘管它們會改變 this 的引用)。您可以將 super 視為類或物件字面量範圍內的變數,方法在其上建立閉包。(但也要注意它實際上不是變數,如上所述。)

透過 super 設定屬性時,屬性設定在 this 上。

示例

在類中使用 super

此程式碼片段取自類示例(線上演示)。在這裡,呼叫 super() 以避免重複 RectangleSquare 之間共有的建構函式部分。

js
class Rectangle {
  constructor(height, width) {
    this.name = "Rectangle";
    this.height = height;
    this.width = width;
  }
  sayName() {
    console.log(`Hi, I am a ${this.name}.`);
  }
  get area() {
    return this.height * this.width;
  }
  set area(value) {
    this._area = value;
  }
}

class Square extends Rectangle {
  constructor(length) {
    // Here, it calls the parent class's constructor with lengths
    // provided for the Rectangle's width and height
    super(length, length);

    // Note: In derived classes, super() must be called before you
    // can use 'this'. Moving this to the top causes a ReferenceError.
    this.name = "Square";
  }
}

超類呼叫靜態方法

您還可以在靜態方法上呼叫 super。

js
class Rectangle {
  static logNbSides() {
    return "I have 4 sides";
  }
}

class Square extends Rectangle {
  static logDescription() {
    return `${super.logNbSides()} which are all equal`;
  }
}
Square.logDescription(); // 'I have 4 sides which are all equal'

在類欄位宣告中訪問 super

在類欄位初始化期間也可以訪問 supersuper 的引用取決於當前欄位是例項欄位還是靜態欄位。

js
class Base {
  static baseStaticField = 90;
  baseMethod() {
    return 10;
  }
}

class Extended extends Base {
  extendedField = super.baseMethod(); // 10
  static extendedStaticField = super.baseStaticField; // 90
}

請注意,例項欄位設定在例項上而不是建構函式的 prototype 上,因此您不能使用 super 訪問超類的例項欄位。

js
class Base {
  baseField = 10;
}

class Extended extends Base {
  extendedField = super.baseField; // undefined
}

在這裡,extendedFieldundefined 而不是 10,因為 baseField 被定義為 Base 例項的自有屬性,而不是 Base.prototype。在這種上下文中,super 只查詢 Base.prototype 上的屬性,因為那是 Extended.prototype 的 [[Prototype]]。

刪除 super 屬性會丟擲錯誤

您不能使用 delete 運算子和 super.propsuper[expr] 來刪除父類的屬性——它會丟擲 ReferenceError

js
class Base {
  foo() {}
}
class Derived extends Base {
  delete() {
    delete super.foo; // this is bad
  }
}

new Derived().delete(); // ReferenceError: invalid delete involving 'super'.

在物件字面量中使用 super.prop

Super 也可以在物件初始化器符號中使用。在此示例中,兩個物件定義了一個方法。在第二個物件中,super 呼叫第一個物件的方法。這得益於 Object.setPrototypeOf(),我們可以使用它將 obj2 的原型設定為 obj1,以便 super 能夠在 obj1 上找到 method1

js
const obj1 = {
  method1() {
    console.log("method 1");
  },
};

const obj2 = {
  method2() {
    super.method1();
  },
};

Object.setPrototypeOf(obj2, obj1);
obj2.method2(); // Logs "method 1"

讀取 super.prop 的方法在繫結到其他物件時行為沒有不同

訪問 super.x 的行為類似於 Reflect.get(Object.getPrototypeOf(objectLiteral), "x", this),這意味著屬性始終在物件字面量/類宣告的原型上查詢,並且解綁和重新繫結方法不會改變 super 的引用。

js
class Base {
  baseGetX() {
    return 1;
  }
}
class Extended extends Base {
  getX() {
    return super.baseGetX();
  }
}

const e = new Extended();
console.log(e.getX()); // 1
const { getX } = e;
console.log(getX()); // 1

物件字面量中也會發生同樣的情況。

js
const parent1 = { prop: 1 };
const parent2 = { prop: 2 };

const child = {
  myParent() {
    console.log(super.prop);
  },
};

Object.setPrototypeOf(child, parent1);
child.myParent(); // Logs "1"

const myParent = child.myParent;
myParent(); // Still logs "1"

const anotherChild = { __proto__: parent2, myParent };
anotherChild.myParent(); // Still logs "1"

只有重置整個繼承鏈才會改變 super 的引用。

js
class Base {
  baseGetX() {
    return 1;
  }
  static staticBaseGetX() {
    return 3;
  }
}
class AnotherBase {
  baseGetX() {
    return 2;
  }
  static staticBaseGetX() {
    return 4;
  }
}
class Extended extends Base {
  getX() {
    return super.baseGetX();
  }
  static staticGetX() {
    return super.staticBaseGetX();
  }
}

const e = new Extended();
// Reset instance inheritance
Object.setPrototypeOf(Extended.prototype, AnotherBase.prototype);
console.log(e.getX()); // Logs "2" instead of "1", because the prototype chain has changed
console.log(Extended.staticGetX()); // Still logs "3", because we haven't modified the static part yet
// Reset static inheritance
Object.setPrototypeOf(Extended, AnotherBase);
console.log(Extended.staticGetX()); // Now logs "4"

從 super 呼叫方法

當將 super.prop 作為函式呼叫時,prop 函式內部的 this 值是當前的 this,而不是 super 指向的物件。例如,super.getName() 呼叫會記錄 "Extended",儘管程式碼看起來等同於 Base.getName()

js
class Base {
  static getName() {
    console.log(this.name);
  }
}

class Extended extends Base {
  static getName() {
    super.getName();
  }
}

Extended.getName(); // Logs "Extended"

這在與靜態私有元素互動時尤為重要。

設定 super.prop 會將屬性設定在 this 上

設定 super 的屬性,例如 super.x = 1,其行為類似於 Reflect.set(Object.getPrototypeOf(objectLiteral), "x", 1, this)。這是理解 super 僅僅是“原型物件的引用”不足的案例之一,因為它實際上是將屬性設定在 this 上。

js
class A {}
class B extends A {
  setX() {
    super.x = 1;
  }
}

const b = new B();
b.setX();
console.log(b); // B { x: 1 }
console.log(Object.hasOwn(b, "x")); // true

super.x = 1 將在 A.prototype 上查詢 x 的屬性描述符(並呼叫在那裡定義的 setter),但 this 值將被設定為 this,在此上下文中為 b。您可以閱讀 Reflect.set 以獲取 targetreceiver 不同時的更多詳細資訊。

這意味著,雖然 獲取 super.prop 的方法通常不易受 this 上下文變化的影響,但那些 設定 super.prop 的方法則會受影響。

js
/* Reusing same declarations as above */

const b2 = new B();
b2.setX.call(null); // TypeError: Cannot assign to read only property 'x' of object 'null'

但是,super.x = 1 仍然會查閱原型物件的屬性描述符,這意味著您不能重寫不可寫屬性,並且會呼叫 setter。

js
class X {
  constructor() {
    // Create a non-writable property
    Object.defineProperty(this, "prop", {
      configurable: true,
      writable: false,
      value: 1,
    });
  }
}

class Y extends X {
  constructor() {
    super();
  }
  foo() {
    super.prop = 2; // Cannot overwrite the value.
  }
}

const y = new Y();
y.foo(); // TypeError: "prop" is read-only
console.log(y.prop); // 1

規範

規範
ECMAScript® 2026 語言規範
# sec-super-keyword

瀏覽器相容性

另見