此篇文章是看了阮老師的es6教程,看到super
關鍵字的時候以爲有必要總結梳理一下,原文仍是參考 ECMAScript 6入門。es6
super
這個關鍵字,既能夠看成函數使用,也能夠看成對象使用。bash
super
做爲函數調用時,表明父類的構造函數。ES6
要求 ,子類的構造函數必須執行一次super
函數。函數
即做爲 函數
使用時下面的代碼時 固定使用套路
:ui
class A {
constrctor(){
}
}
class B extends A {
constructor() {
super();
}
}
複製代碼
上面代碼中的super()表明的誰??this
子類 B
的構造函數中的super()
,表明 B
調用父類 A
的構造函數執行。spa
注意⚠️: 雖然這裏的 super()
表明了的 父類 A
的構造函數,可是返回的倒是 子類 B
的實例,即 super()
內部的this 指的是 B, 所以 super()
在這裏至關於 A.prototype.constructor.call(this)
。prototype
用一個大栗子來證實個人論點:code
class A {
constrctor(){
console.log(new.target.name)
}
}
class B extends A{
constructor(){
super()
}
}
new A() // A
new B() // B
複製代碼
在這段熱氣騰騰的代碼中, new.target
指向當前正在執行的函數。cdn
囉嗦一下:對象
new
是從構造函數生成的實例對象的命令。ES6 爲 new
命令引入了一個 new.target
屬性,該屬性通常用在構造函數之中,返回new命令做用於的那個構造函數。
能夠看到,在 super()
執行時,它指向的是子類 B
的構造函數,而不是父類 A
的構造函數。即 super()
內部的 this 指向的是 B
。
還有一點須要注意 ⚠️ :
做爲函數時,super()只能用在子類的構造函數中,用在其餘地方報錯。
// 錯誤寫法
class A {}
class B extends A {
m() {
super(); // 報錯
}
}
複製代碼
當super 做爲函數的時候須要注意如下三點:
super
函數。// 再次重申,這是固定寫法
class A {
constructor() {}
}
class B extends A {
constructor() {
super();// 這裏表示 A.constructor()
}
}
複製代碼
super()
表明的是 子類調用父類的構造函數執行,這時候 super()
中的this,即 父類.constructor
中的 this
,指向的是子類。3.super()只能用在子類的構造函數之中,用在其餘地方就會報錯。
super
做爲對象時,在普通方法中,指向父類的原型對象,在靜態方法中指向父類。
上代碼:
class A {
p(){
return 2
}
}
class B extends A {
constrctor(){
super();
console.log(super.p());//2
}
}
let b = new B();
複製代碼
咱們發現 在子類 B
中super.p()
執行結果爲2
。咱們猜想這裏的supsuper.p === A.prototype.p
,驗證一下發現結果是 true
:
class A {
p() {
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.p===A.prototype.p); // true
}
}
let b = new B();
複製代碼
也就是說這個時候 super
在普通的方法中,指向的是 A.prototype
即子類中的super
指向父類的原型對象。
⚠️注意點 1. :因爲子類中的super
指向父類的原型對象,因此定義在父類實例上的方法或屬性,是沒法經過super
調用的。
class A {
constructor() {
this.s = 3;
}
}
A.prototype.x = 2;
class B extends A {
constructor() {
super();
console.log(super.x) // 2 這裏能夠獲取到父類原型上的x屬性
}
get m(){
return super.s
}
}
let b = new B();
console.log(b.m)// undefined 不能獲取到定義在父類實例上的s屬性
複製代碼
經過上面的代碼咱們發現:
子類 B
能夠經過super
獲取到父類定義在原型上的屬性,可是定義在父類 A
的實例上的屬性,沒法獲取到。
注意點2⚠️:this指向
ES6 規定,在子類普通方法中經過 super
調用父類的方法時,方法內部的 this
指向當前的子類實例。
class A {
constructor() {
this.x = 1;
}
print() {
console.log(this.x);
}
}
class B extends A {
constructor() {
super();
this.x = 2;
}
m() {
super.print();// 這裏等同於 A.proptotype.print()
}
}
let b = new B();
b.m() // 2
複製代碼
上面代碼中,super.print()
雖然調用的是A.prototype.print()
,可是 A.prototype.print()
內部的this指向子類B的實例,致使輸出的是2,而不是1。也就是說,實際上執行的是 super.print.call(this)
。
注意點3⚠️:經過super
進行賦值操做
因爲 this
指向子類實例,因此若是經過 super
對某個屬性賦值,這時super
就是this
,賦值的屬性會變成子類實例的屬性。
class A {
constructor() {
this.x = 1;
}
}
class B extends A {
constructor() {
super();
this.x = 2;
super.x = 3;// 此時的 super 就是 b
console.log(super.x); // undefined 等用因而 A.prototype.x
console.log(this.x); // 3
}
}
let b = new B();
複製代碼
經過這兩段代碼咱們發現了一個問題,當我經過 super
取值的時候取的是父類的原型上屬性,可是當我經過 super
賦值的時候這時候 super
指向的是子類的實例。
經過上面的三個栗子得出, super
做爲對象在普通方法中應用時:
super
指向父類的原型對象,因此定義在父類實例上的方法或屬性,是沒法經過super
調用的。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 指的是父類,Parent
super.myMethod(msg);
}
myMethod(msg) {
// 普通函數 此時 super 是指 Parent.prototype
super.myMethod(msg);
}
}
Child.myMethod(1); // static 1
var child = new Child();
child.myMethod(2); // instance 2
複製代碼
上面代碼中,super在靜態方法之中指向父類,在普通方法之中指向父類的原型對象。
注意點1 ⚠️
在子類的靜態方法中經過 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();// A.print 中的this指向當前的子類
}
}
B.x = 3;
B.m() // 3
複製代碼
上面代碼中,靜態方法 B.m
裏面,super.print
指向父類的靜態方法。這個方法裏面的 this
指向的是 B
,而不是 B
的實例。
在子類的靜態方法中經過super
調用父類的方法時,方法內部的this
指向當前的子類,而不是子類的實例。
super
做爲函數,super()
表明的就是父類構造函數,裏面的this
就是類的實例。super
做爲對象,在普通的方法中super.
的語法指向的是父類的原型對象,在靜態方法中使用super.
語法的話就去父類的靜態方法中找就好了。至於this
指向問題,記住一點:若是在一個方法前,加上static
關鍵字,就表示該方法不會被實例繼承,而是直接經過類來調用,因此靜態方法中的this
只會指類而不是實例。