The usage of the super keyword
Basic Concepts of the super Keyword
The super
keyword was introduced in ECMAScript 6 and is primarily used in subclasses to call the constructor or methods of the parent class. It provides two usage modes: as a function call and as an object. When used as a function call, it can only be used in the constructor of a subclass; when used as an object, it can be used in any method of the subclass.
class Parent {
constructor(name) {
this.name = name;
}
sayHello() {
return `Hello, ${this.name}`;
}
}
class Child extends Parent {
constructor(name, age) {
super(name); // Called as a function
this.age = age;
}
greet() {
return `${super.sayHello()}! You are ${this.age} years old.`; // Used as an object
}
}
const child = new Child('Alice', 10);
console.log(child.greet()); // Output: Hello, Alice! You are 10 years old.
Using super in Constructors
In the constructor of a subclass, super
must be called before using the this
keyword; otherwise, a ReferenceError
will be thrown. This is because the this
object of the subclass must first be shaped by the parent class's constructor, inheriting the same instance properties and methods as the parent class, before being further processed to add the subclass's own instance properties and methods.
class Animal {
constructor(name) {
this.name = name;
this.speed = 0;
}
}
class Rabbit extends Animal {
constructor(name, earLength) {
// super() must be called first
super(name);
this.earLength = earLength;
}
// Incorrect usage, will throw a ReferenceError
/*
constructor(name, earLength) {
this.earLength = earLength; // Error!
super(name);
}
*/
}
const rabbit = new Rabbit('White Rabbit', 10);
console.log(rabbit.name); // White Rabbit
console.log(rabbit.earLength); // 10
Calling Parent Class Methods with super
When super
is used as an object, it can call methods of the parent class. In regular methods, super
refers to the parent class's prototype object; in static methods, super
refers to the parent class itself.
class Person {
constructor(name) {
this.name = name;
}
introduce() {
return `My name is ${this.name}`;
}
}
class Student extends Person {
constructor(name, grade) {
super(name);
this.grade = grade;
}
introduce() {
return `${super.introduce()} and I'm in grade ${this.grade}`;
}
static sayHello() {
return 'Hello from Student class';
}
}
class CollegeStudent extends Student {
static sayHello() {
return `${super.sayHello()} (now in college)`;
}
}
const student = new Student('Bob', 5);
console.log(student.introduce()); // My name is Bob and I'm in grade 5
console.log(CollegeStudent.sayHello()); // Hello from Student class (now in college)
super and Static Methods
In static methods, super
refers to the parent class rather than the parent class's prototype object. This allows subclasses to call static methods of the parent class.
class Base {
static getMessage() {
return 'Base static message';
}
getInstanceMessage() {
return 'Base instance message';
}
}
class Derived extends Base {
static getMessage() {
return `${super.getMessage()} + Derived static message`;
}
getInstanceMessage() {
return `${super.getInstanceMessage()} + Derived instance message`;
}
}
console.log(Derived.getMessage()); // Base static message + Derived static message
const derived = new Derived();
console.log(derived.getInstanceMessage()); // Base instance message + Derived instance message
Using super in Object Literals
ES6 allows the use of the super
keyword in object literals, but it must be used with method shorthand syntax.
const parent = {
greet() {
return 'Hello from parent';
}
};
const child = {
__proto__: parent,
greet() {
return `${super.greet()} and hello from child`;
}
};
console.log(child.greet()); // Hello from parent and hello from child
Binding of super
The binding of super
is static and is determined when the method is defined, not when it is called. This means that even if the method is assigned to another object, super
still refers to the original parent class.
class A {
say() {
return 'A';
}
}
class B extends A {
say() {
return `${super.say()}B`;
}
getSayMethod() {
return this.say;
}
}
const b = new B();
console.log(b.say()); // AB
const obj = {
say() {
return 'obj';
}
};
// Assigning the method to another object
const say = b.getSayMethod();
console.log(say.call(obj)); // Still AB, not objB
super and Arrow Functions
Arrow functions do not have their own super
binding; they inherit the super
binding from the surrounding context. This allows the use of super
in arrow functions to avoid this
binding issues.
class Parent {
greet() {
return 'Parent greeting';
}
}
class Child extends Parent {
constructor() {
super();
this.greet = () => super.greet();
}
// Arrow function in a regular method
getGreeter() {
return () => super.greet();
}
}
const child = new Child();
console.log(child.greet()); // Parent greeting
const greeter = child.getGreeter();
console.log(greeter()); // Parent greeting
Behavior of super in Multiple Inheritance
JavaScript does not natively support multiple inheritance, but it can be simulated using mixins. In such cases, the behavior of super
requires special attention.
class A {
method() {
return 'A';
}
}
const B = {
method() {
return `${super.method()}B`;
}
};
const C = {
method() {
return `${super.method()}C`;
}
};
// Setting up the prototype chain
Object.setPrototypeOf(B, A.prototype);
Object.setPrototypeOf(C, B);
class D extends A {
method() {
return `${super.method()}D`;
}
}
// Mixing C into D
Object.assign(D.prototype, C);
const d = new D();
console.log(d.method()); // ACD
super and Proxy
When a class is wrapped with a Proxy
, the behavior of super
may be affected because the Proxy
can intercept property access.
class Base {
value = 10;
getValue() {
return this.value;
}
}
const handler = {
get(target, prop, receiver) {
if (prop === 'value') {
return 20;
}
return Reflect.get(target, prop, receiver);
}
};
class Derived extends Base {
getValue() {
return super.getValue();
}
}
const proxy = new Proxy(new Derived(), handler);
console.log(proxy.getValue()); // 20, because the Proxy intercepts access to 'value'
Using super in Asynchronous Methods
super
can also be used in asynchronous methods, with behavior consistent with synchronous methods.
class AsyncBase {
async fetchData() {
return new Promise(resolve => {
setTimeout(() => resolve('Base data'), 100);
});
}
}
class AsyncDerived extends AsyncBase {
async fetchData() {
const baseData = await super.fetchData();
return `${baseData} + Derived data`;
}
}
(async () => {
const derived = new AsyncDerived();
console.log(await derived.fetchData()); // Base data + Derived data
})();
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:类的继承extends
下一篇:getter和setter方法