super 關鍵字,既可以當作函數使用,也可以當作對象使用。在這兩種情況下,它的用法完全不同。
1、super當做函數使用
super 作為函數調用時,代表父類的構造函數。ES6 要求,子類的構造函數必須執行一次 super() 函數。注意:作為函數時,super() 只能用在子類的構造函數之中,用在其他地方就會報錯。
class A {}
class B extends A {
constructor() {
super();
}
}
super 作為函數調用時,內部的 this 指的是子類實例
class A { constructor() { this.show(); } } class B extends A { constructor() { super(); } show(){ console.log('實例'); } static show(){ console.log('子類'); } } new B() //輸出 '實例' ,new B 時觸發了 B 的構造函數,所以觸發了 super 方法,即觸發了父類 A 的構造函數,此時的 this.show 的 this 指的是子類
2、super 作為對象使用
super 作為對象時,在普通方法中,指向父類的原型對象;在靜態方法中,指向父類。
2.1、super在普通方法中(即非靜態方法)及此時的 this 關鍵字指向
class A { p() { return 2; } } class B extends A { constructor() { super(); console.log(super.p()); // 2 此時的super指向父類原型對象,即 A.prototype } } let b = new B(); //2
由於在普通方法中的 super 指向父類的原型對象,所以如果父類上的方法或屬性是定義在實例上的,就無法通過 super 調用的。如下所示:
class A { constructor() { //在構造函數上定義的屬性和方法相當於定義在父類實例上的,而不是原型對象上 this.p = 2; } } class B extends A { get m() { return super.p; } } let b = new B(); console.log(b.m) // undefined
在子類普通方法中通過 super 調用父類的方法時,方法內部的 this 指向的是當前的子類實例。
class A { constructor() { this.x = 1; } print() { console.log(this.x); } } class B extends A { constructor() { super(); this.x = 2; super.y = 123; //如果通過super對某個屬性賦值,這時super就是this,賦值的屬性會變成子類實例的屬性。 } m() { super.print(); } }
let b = new B(); b.m() // 2 console.log(b.y); //123
2.2、super在靜態方法中及此時的 this 關鍵字指向
super作為對象,用在靜態方法之中,這時 super 將直接指向父類,而不是父類的原型對象。
class Parent { static myMethod(msg) { console.log('static', msg); } myMethod(msg) { console.log('instance', msg); } } class Child extends Parent { static myMethod(msg) { super.myMethod(msg); } myMethod(msg) { super.myMethod(msg); } } Child.myMethod(1); // static 1 var child = new Child(); child.myMethod(2); // instance 2
在子類的靜態方法中通過 super 調用父類的方法時,方法內部的 this 指向當前的子類,而不是子類的實例。
class A { constructor() { this.x = 1; } static print() { console.log(this.x); } } class B extends A { constructor() { super(); this.x = 2; } static m() { super.print(); } } B.x = 3; B.m() // 3
