概述
- class可以通过
extends实现继承,让子类继承父类的属性和方法。
- ES6规定,子类必须在
constructor方法中调用super,否则就报错。因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再添加子类自己的实例属性和方法。也就是说,新建子类实例时,父类的构造函数必定会先运行一次。
class Person{
constructor(name, age){
this.name = name;
this.age = age;
}
sayName(){
console.log('my name is' + this.name);
}
}
class Student extends Person{
constructor(name, age, grade){
super(name, age);
this.grade = grade;
}
sayName(){
super.sayName();
console.log('i am ' + this.grade);
}
}
let s = new Student('张三', 18, '三年级');
console.log(s)
s.sayName()
- 在子类的构造函数中,只有调用
super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,必须先完成父类的继承,只有super()方法才能让子类实例继承父类。
- 如果子类没有定义
constructor方法,这个方法会默认添加,并且里面会调用super()。
Object.getPrototypeOf()方法可以用来判断一个类是否继承了另一个类。
class Point { }
class ColorPoint extends Point { }
Object.getPrototypeOf(ColorPoint) === Point
私有属性、方法的继承
- 父类所有的属性和方法都会被子类继承,除了私有的属性和方法。
class Foo {
#p = 1;
#m() {
console.log('hello');
}
}
class Bar extends Foo {
constructor() {
super();
console.log(this.#p);
this.#m();
}
}
- 只有父类定义了私有属性的读写方法,子类才可以通过这些方法读写私有属性。
class Foo {
#p = 1;
getP() {
return this.#p;
}
}
class Bar extends Foo {
constructor() {
super();
console.log(this.getP());
}
}
静态属性、方法的继承
class A {
static hello() {
console.log('hello world');
}
}
class B extends A {}
B.hello()
- 静态属性是通过
浅拷贝实现继承的,如果父类的静态属性的值是一个对象,那么子类的静态属性也会指向这个对象。
class A {
static foo = { n: 100 };
}
class B extends A {
constructor() {
super();
B.foo.n--;
}
}
const b = new B();
B.foo.n
A.foo.n
super
super关键字既可以当作函数使用,又可以当作对象使用。
作为函数
- 作为函数调用时,只能用在子类的构造函数中,用在其他地方会报错,此时
super代表的是父类的构造函数constructor。
class A {
constructor() {
console.log(new.target.name);
}
}
class B extends A {
constructor() {
super();
}
}
new A()
new B()
- 由于
super在子类构造函数中执行时,子类的属性和方法还没有绑定到this,所以如果存在同名属性,此时拿到的是父类的属性。
class A {
name = 'A';
constructor() {
console.log('My name is ' + this.name);
}
}
class B extends A {
name = 'B';
}
const b = new B();
作为对象
普通方法
- 当
super作为对象时,在普通方法中指向父类的原型对象,所以定义在父类实例上的方法或属性是无法通过super调用的,但是定义在父类原型对象上的属性或方法却可以调用。
class A {
p() {
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.p());
}
}
let b = new B();
- 在子类普通方法中通过
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()
静态方法
- 当
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);
var child = new Child();
child.myMethod(2);
- 在子类的静态方法中通过
super调用父类的方法时,方法内部的this指向当前的子类,而不是子类实例。
class A {
static x = 1;
static print() {
console.log(this.x);
}
}
class B extends A {
static x = 2;
static m() {
super.print();
}
}
B.m()