1、extends
ES6通过extends关键字实现继承。ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。因此,如果子类显示定义了constructor方法,那么必须在constructor方法中显示调用super方法,如果子类没有定义constructor方法,这个方法会被默认添加
// 子类未显示定义constructor方法
class ColorPoint extends Point {
}
// 等同于
class ColorPoint extends Point {
constructor(...args) {
super(...args);
}
}
(显示定义子类的构造函数)在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,基于父类实例,只有super方法才能调用父类实例。
父类的静态方法,也会被子类继承
class A {
static hello() {
console.log('hello world')
}
}
class B extends A {
}
B.hello()
// hello world
2、super
super关键字的用途
- 当作函数使用
- 当作对象使用
super当作函数使用时, 代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。作为函数时,super()只能用在子类的构造函数之中。
class A {}
class B extends A {
constructor() {
super();
}
}
super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B的实例,因此super()在这里相当于A.prototype.constructor.call(this)。
super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。
class A {
p() {
return 2
}
}
class B extends A {
constructor() {
super()
console.log(super.p())
}
}
let b = new B()
上面代码中,子类B当中的super.p(),就是将super当作一个对象使用。这时,super在普通方法之中,指向A.prototype,所以super.p()就相当于A.prototype.p()。
由于super作为对象使用时指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的,但是可以通过this获取
class A {
constructor() {
this.p = 2
}
}
class B extends A {
get m() {
console.log('super', super.p)
<!--undefined-->
console.log('this', this.p)
// 2
}
}
let b = new B()
b.m
在子类普通方法中通过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()
}
}
let b = new B()
b.m()
// 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
网友评论