引子
在前端框架中使用類(class)繼承的當屬擁有強大生態的React,我們在react中自定義一個元件往往會這樣子寫:
class MyComponent extends React.Component{
constructor(props){
this.state={
user:'React',
display:true
}
}
render(){
return(
<div>
<p>{this.state.user}</p>
</div>
)
}
}
複製程式碼
上面就使用到了class繼承,繼承react.component的屬性和方法,在服務端,我們使用nodeJs最新的框架koa2,所有的繼承都是使用es6的class來進行繼承。那麼廢話不多說,一起來看一看它的廬山真面目。
簡介
class Parent{
}
class Child extends Parent{
constructor(x,y,color){
super(x,y);//呼叫父類的constructor(x,y)
this.color=color;
}
toString(){
return this.color+''+super.toString();//super.toString();呼叫了父類的toString()方法
}
}
複製程式碼
上面定義了一個Child類,該類通過extends關鍵字繼承了Parent類的所有屬性和方法,constructor方法和toString方法中都出現了super關鍵字,它在這裡表示父類的建構函式,用來新建立父類的this物件。
子類必須在constructor方法中呼叫super的方法,否則新建例項會報錯,這是因為子類沒有自己的this物件,而是繼承父類的this物件,然後對其進行加工,不呼叫super方法,子類就得不到this物件。
class Parent{
/*........*/
}
class Child extends Parent{
constructor(x,y,color){
}
}
let cp=new Child()//ReferenceError;
複製程式碼
上面的程式碼中,Child 雖然繼承了Parent類,但是在自己的的建構函式中沒有呼叫super方法,導致新建例項報錯。
在這裡我們就得聊一聊es5和es6的繼承實質,在es5的繼承實質是先創造子類的例項物件this,然後再將父類的方法新增到this上面,也就是Parent.apply(this)。而es6的繼承機制完全不同,實質是先創造父類的例項物件this(所以必須呼叫super方法),然後使用子類的建構函式去修改this。
注意點
1.如果子類沒有定義constructor方法,那麼這個方法會被預設新增,如下程式碼,也就是說無論有沒有顯示定義,任何一個子類都有constructor方法。
class dog extends Aimals{
constructor (...args){
super(...args)
}
}
//兩者等價
class dog extends Aimals{
constructor (...args){
super(...args)
}
}
複製程式碼
2.另一個要注意的地方是,在子類的建構函式中,只有呼叫super之後才可以使用this關鍵字,否則會報錯,這是因為子類例項的構建是基於父類例項的加工,只有super方法才能返回父類的例項。
class Animals{
constructor (name,age)
this.name=name;
this.age=age;
}
}
class dog extends Animals{
constructor (name,age,color){
this.color=color; //ReferenceError
super(name,age)
this.age=age;
this.color=color; //正確
}
}
複製程式碼
上面的程式碼,子類的constructor方法沒有呼叫super之前就使用this關鍵字,結果報錯,而在super之後就是正確的。