ES6 Class中的super关键字详解

589 阅读2分钟

super关键字在类中有两种完全不同的表现形式:当作函数使用、当作对象使用

super关键字当作函数使用

  • ES6要求,子类的构造函数中必须执行一次super函数;
  • 在子类的构造函数中,super()表示父类的构造函数;
    • super()就相当于A.prototype.constructor.call(this)
  • super作为函数时,只能在子类的构造函数中使用,在其他地方使用会报错;
class A {}

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

super关键字当作对象使用

  • 在普通方法中,super指向父类的原型对象;在静态方法中,super指向父类

  • 在如下代码中,子类B构造函数中的super.c(),就是将super当作一个对象使用:

    • 这时,super在普通方法中,则super指向A.prototype,所以super.c()就相当于A.prototype.c()
    class A {
        c() {
            return 2;
        }
    }
    
    class B extends A {
        constructor() {
            super();
            console.log(super.c()); // 2
        }
    }
    let b = new B();
    
  • 通过super调用父类的方法时,super会绑定子类的this

    • 如下代码中,super.s()虽然实际调用的是A.prototype.s(),但是A.prototype.s()会绑定子类Bthis,导致输出的是2,而不是1;也就是说,实际上执行的是super.s.call(this)
      class A {
          constructor() {
              this.x = 1;
          }
          
          a1() {
              console.log(this.x);
          }
      }
      
      class B extends A {
          constructor() {
              super();
              this.x = 2;
          }
          
          b1() {
              super.a1();
          }
      }
      
      let b = new B();
      b.b1() // 2
      
  • 由于通过super调用父类方法时,会绑定子类的this,所以如果通过super对某个属性赋值,这时super就是this,赋值的属性会变成子类实例的属性:

    • 如下代码中,super.x = 3,这时就等同于对this.x = 3,而当读取super.x时,读的是A.prototype.x,所以返回undefined
      class A {
          constructor() {
              this.x = 1;
          }
      }
      
      class B extends A {
          constructor() {
              super();
              this.x = 2;
              super.x = 3;
              console.log(super.x); // undefined
              console.log(this.x); // 3
          }
      }
      
      let b = new B();
      
  • 注意,使用super时,必须显式指定是作为函数、还是作为对象使用,否则会报错:

    • 如下代码中,console.log(super)中的super,无法看出是作为函数使用,还是作为对象使用,所以 JavaScript引擎解析代码时就会报错:
      class A {}
      
      class B extends A {
          constructor() {
              super();
              console.log(super); // 报错
          }
      }
      

参考原文:
深入浅析ES6 Class中的super关键字
es6类的继承,看完还不会就地埋了吧