
引子
在前端框架中使用类(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之后就是正确的。