super
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since March 2017.
super
关键字用于访问对象文字或类的 [[Prototype]] 上的属性,或调用超类的构造函数。
¥The super
keyword is used to access properties on an object literal or class's [[Prototype]], or invoke a superclass's constructor.
super.prop
和 super[expr]
表达式在 classes 和 对象字面量 中的任何 方法定义 中都有效。super(...args)
表达式在类构造函数中有效。
¥The super.prop
and super[expr]
expressions are valid in any method definition in both classes and object literals. The super(...args)
expression is valid in class constructors.
Try it
语法
描述
¥Description
super
关键字有两种使用方式:作为 "函数调用" (super(...args)
),或作为 "属性查找"(super.prop
和 super[expr]
)。
¥The super
keyword can be used in two ways: as a "function call" (super(...args)
), or as a "property lookup" (super.prop
and super[expr]
).
注意:
super
是一个关键字,这些是特殊的语法结构。super
不是指向原型对象的变量。尝试读取super
本身就是SyntaxError
。¥Note:
super
is a keyword and these are special syntactic constructs.super
is not a variable that points to the prototype object. Attempting to readsuper
itself is aSyntaxError
.jsconst child = { myParent() { console.log(super); // SyntaxError: 'super' keyword unexpected here }, };
在派生类(带有 extends
)的 构造函数 主体中,super
关键字可能会显示为 "函数调用" (super(...args)
),必须在使用 this
关键字之前和构造函数返回之前调用它。它调用父类的构造函数并绑定父类的公共字段,之后派生类的构造函数可以进一步访问和修改 this
。
¥In the constructor body of a derived class (with extends
), the super
keyword may appear as a "function call" (super(...args)
), which must be called before the this
keyword is used, and before the constructor returns. It calls the parent class's constructor and binds the parent class's public fields, after which the derived class's constructor can further access and modify this
.
"属性查找" 形式可用于访问对象文字或类的 [[Prototype]] 的方法和属性。在类的主体中,super
的引用可以是超类的构造函数本身,也可以是构造函数的 prototype
,具体取决于执行上下文是实例创建还是类初始化。有关更多详细信息,请参阅示例部分。
¥The "property lookup" form can be used to access methods and properties of an object literal's or class's [[Prototype]]. Within a class's body, the reference of super
can be either the superclass's constructor itself, or the constructor's prototype
, depending on whether the execution context is instance creation or class initialization. See the Examples section for more details.
请注意,super
的引用是由声明 super
的类或对象文字决定的,而不是调用该方法的对象。因此,取消绑定或重新绑定方法不会更改其中 super
的引用(尽管它们确实更改了 this
的引用)。你可以将 super
视为类或对象文字范围中的变量,方法在其上创建闭包。(但也要注意,正如上面所解释的,它实际上不是一个变量。)
¥Note that the reference of super
is determined by the class or object literal super
was declared in, not the object the method is called on. Therefore, unbinding or re-binding a method doesn't change the reference of super
in it (although they do change the reference of this
). You can see super
as a variable in the class or object literal scope, which the methods create a closure over. (But also beware that it's not actually a variable, as explained above.)
当通过 super
设置属性时,该属性将改为在 this
上设置。
¥When setting properties through super
, the property is set on this
instead.
示例
在课堂上使用 super
¥Using super in classes
此代码片段取自 类样本 (现场演示)。这里调用 super()
是为了避免重复 Rectangle
和 Square
之间共有的构造函数部分。
¥This code snippet is taken from the classes sample (live demo). Here super()
is called to avoid duplicating the constructor parts' that are common between Rectangle
and 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-calling static methods
你还可以在 static 方法上调用 super。
¥You are also able to call super on static methods.
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
¥Accessing super in class field declaration
super
也可以在类字段初始化期间访问。super
的引用取决于当前字段是实例字段还是静态字段。
¥super
can also be accessed during class field initialization. The reference of super
depends on whether the current field is an instance field or a static field.
class Base {
static baseStaticField = 90;
baseMethod() {
return 10;
}
}
class Extended extends Base {
extendedField = super.baseMethod(); // 10
static extendedStaticField = super.baseStaticField; // 90
}
请注意,实例字段是在实例上设置的,而不是在构造函数的 prototype
上设置的,因此你不能使用 super
来访问超类的实例字段。
¥Note that instance fields are set on the instance instead of the constructor's prototype
, so you can't use super
to access the instance field of a superclass.
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]]。
¥Here, extendedField
is undefined
instead of 10, because baseField
is defined as an own property of the Base
instance, instead of Base.prototype
. super
, in this context, only looks up properties on Base.prototype
, because that's the [[Prototype]] of Extended.prototype
.
删除超级属性会抛出错误
¥Deleting super properties will throw an error
你不能使用 delete
运算符 和 super.prop
或 super[expr]
来删除父类的属性 - 它会抛出 ReferenceError
。
¥You cannot use the delete
operator and super.prop
or super[expr]
to delete a parent class' property — it will throw a 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
¥Using super.prop in object literals
Super 也可以用在 对象初始值设定项 表示法中。在此示例中,两个对象定义了一个方法。在第二个对象中,super
调用第一个对象的方法。这在 Object.setPrototypeOf()
的帮助下工作,我们可以将 obj2
的原型设置为 obj1
,以便 super
能够在 obj1
上找到 method1
。
¥Super can also be used in the object initializer notation. In this example, two objects define a method. In the second object, super
calls the first object's method. This works with the help of Object.setPrototypeOf()
with which we are able to set the prototype of obj2
to obj1
, so that super
is able to find method1
on obj1
.
const obj1 = {
method1() {
console.log("method 1");
},
};
const obj2 = {
method2() {
super.method1();
},
};
Object.setPrototypeOf(obj2, obj1);
obj2.method2(); // Logs "method 1"
读取 super.prop 的方法在绑定到其他对象时不会有不同的行为
¥Methods that read super.prop do not behave differently when bound to other objects
访问 super.x
的行为与 Reflect.get(Object.getPrototypeOf(objectLiteral), "x", this)
类似,这意味着始终在对象文字/类声明的原型上查找属性,并且取消绑定和重新绑定方法不会更改 super
的引用。
¥Accessing super.x
behaves like Reflect.get(Object.getPrototypeOf(objectLiteral), "x", this)
, which means the property is always seeked on the object literal/class declaration's prototype, and unbinding and re-binding a method won't change the reference of 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
同样的情况也发生在对象字面量中。
¥The same happens in object literals.
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
的引用。
¥Only resetting the entire inheritance chain will change the reference of 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 调用方法
¥Calling methods from super
当将 super.prop
作为函数调用时,prop
函数内部的 this
值是当前的 this
,而不是 super
指向的对象。例如,super.getName()
调用记录 "Extended"
,尽管代码看起来与 Base.getName()
等效。
¥When calling super.prop
as a function, the this
value inside the prop
function is the current this
, not the object that super
points to. For example, the super.getName()
call logs "Extended"
, despite the code looking like it's equivalent to Base.getName()
.
class Base {
static getName() {
console.log(this.name);
}
}
class Extended extends Base {
static getName() {
super.getName();
}
}
Extended.getName(); // Logs "Extended"
这在与 静态私有属性 互动时尤其重要。
¥This is especially important when interacting with static private properties.
设置 super.prop 来设置 this 的属性
¥Setting super.prop sets the property on this instead
设置 super
的属性(例如 super.x = 1
)的行为与 Reflect.set(Object.getPrototypeOf(objectLiteral), "x", 1, this)
类似。这是将 super
简单理解为 "原型对象的引用" 的情况之一,因为它实际上将属性设置在 this
上。
¥Setting properties of super
, such as super.x = 1
, behaves like Reflect.set(Object.getPrototypeOf(objectLiteral), "x", 1, this)
. This is one of the cases where understanding super
as simply "reference of the prototype object" falls short, because it actually sets the property on this
instead.
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
。当 target
和 receiver
不同时,你可以阅读 Reflect.set
了解更多有关情况的详细信息。
¥super.x = 1
will look for the property descriptor of x
on A.prototype
(and invoke the setters defined there), but the this
value will be set to this
, which is b
in this context. You can read Reflect.set
for more details on the case when target
and receiver
differ.
这意味着虽然获取 super.prop
的方法通常不易受到 this
上下文中更改的影响,但设置 super.prop
的方法则不然。
¥This means that while methods that get super.prop
are usually not susceptible to changes in the this
context, those that set super.prop
are.
/* 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。
¥However, super.x = 1
still consults the property descriptor of the prototype object, which means you cannot rewrite non-writable properties, and setters will be invoked.
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
规范
Specification |
---|
ECMAScript Language Specification # sec-super-keyword |
浏览器兼容性
BCD tables only load in the browser
也可以看看
¥See also