yaoningvital / blog

my blog
31 stars 4 forks source link

关于class中super的指向 #153

Open yaoningvital opened 5 years ago

yaoningvital commented 5 years ago

super 这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。

1、super 作为函数使用,代表父类的构造函数。

ES6要求,子类的构造函数,必须执行一次super():

class A {}

class B extends A {
  constructor() {
    super();
  }
}

注意

  1. super() 在这里相当于 A.prototype.constructor.call(this)
  2. super作为函数使用时,只能用在子类的构造函数中,用在其他地方会报错。

2、super 作为对象使用时,在构造函数或者在实例方法中,指向的是父类的原型对象。

如:

class A {
  p() {
    return 2;
  }
}

class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2  这里的super指向父类A的原型 super===A.prototype
  }
}

let b = new B();

3、super 作为对象使用时,在构造函数或者在实例方法中,如果通过super对某个属性赋值,这时super指向的是子类的实例。

这时super就是this,赋值的属性会变成子类实例的属性。

class A {
  constructor() {
    this.x = 1;
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
    super.x = 3; // 通过super对属性赋值,此时super指向实例 this
    console.log(super.x); // undefined  这里的super指向的是 A.prototype
    console.log(this.x); // 3
  }
}

let b = new B();

4、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); // 这里的super指向父类Parent
  }

  myMethod(msg) {
    super.myMethod(msg); // 这里的 super 指向父类的原型,即 Parent.prototype
  }
}

Child.myMethod(1); // static 1

var child = new Child();
child.myMethod(2); // instance 2

注意:

注意, 1、使用super的时候,必须显式指定是作为函数、还是作为对象使用,否则会报错。

class A {}

class B extends A {
  constructor() {
    super();
    console.log(super); // 报错
  }
}