super
super 关键字用于访问对象字面量或类的 [[Prototype]] 上的属性,或者调用超类的构造函数。
super.prop 和 super[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"
语法
super()
super(arg1)
super(arg1, arg2)
super(arg1, arg2, /* …, */ argN)
super.propertyOnParent
super[expression]
描述
super 关键字可以通过两种方式使用:“函数调用”(super(...args)),或“属性查找”(super.prop 和 super[expr])。
注意:super 是一个关键字,这些是特殊的语法结构。super 不是指向原型对象的变量。尝试读取 super 本身会抛出 SyntaxError。
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() 以避免重复 Rectangle 和 Square 之间共有的构造函数部分。
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。
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
在类字段初始化期间也可以访问 super。super 的引用取决于当前字段是实例字段还是静态字段。
class Base {
static baseStaticField = 90;
baseMethod() {
return 10;
}
}
class Extended extends Base {
extendedField = super.baseMethod(); // 10
static extendedStaticField = super.baseStaticField; // 90
}
请注意,实例字段设置在实例上而不是构造函数的 prototype 上,因此您不能使用 super 访问超类的实例字段。
class Base {
baseField = 10;
}
class Extended extends Base {
extendedField = super.baseField; // undefined
}
在这里,extendedField 是 undefined 而不是 10,因为 baseField 被定义为 Base 实例的自有属性,而不是 Base.prototype。在这种上下文中,super 只查找 Base.prototype 上的属性,因为那是 Extended.prototype 的 [[Prototype]]。
删除 super 属性会抛出错误
您不能使用 delete 运算符和 super.prop 或 super[expr] 来删除父类的属性——它会抛出 ReferenceError。
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。
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 的引用。
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
对象字面量中也会发生同样的情况。
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 的引用。
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()。
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 上。
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 以获取 target 和 receiver 不同时的更多详细信息。
这意味着,虽然 获取 super.prop 的方法通常不易受 this 上下文变化的影响,但那些 设置 super.prop 的方法则会受影响。
/* 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。
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 |
浏览器兼容性
加载中…