Javascript高级程序设计-类的继承

161 阅读2分钟

1.继承基础

使用extends关键字,就可以继承任何拥有[[Construct]]和原型的对象。

class Vehicle {}

let b = new Bus()
b instance of Bus === true
b instance of Vehicle === true

function Person() {}

// 继承构造函数
class Engineer extends Person {}

let e = new Engineer()
e instance of Engineer === true
e instance of Person === true

派生类都会通过原型链访问到类和原型上定义的方法。this 的值会反映调用相应方法的实例或者类

class Vehicle {
  identifyPrototype(id) {
    console.log(id, this)
  }
  static identifyClass(id) {
    console.log(id, this)
  }
}

class Bus extends Vehicle {}

let v = new Vehicle()
let b = new Bus()

b.identifyPrototype('bus') // bus, Bus {}
v.identifyPrototype('vehicle') // vehicle, Vehicle {}

Bus.identifyClass('bus') // bus, Bus {}
Vehicle.identifyClass('vehicle') // vehicle, Vehicle {}

2.构造函数、HomeObject 和 super()

派生类方法可以通过super关键字引用他们的原型。 super只能在派生类中使用,且仅限于类构造函数、实例方法和静态方法内部。 在类构造函数中使用super可以调用父类的构造函数 在静态方法中可以通过super调用父类的静态方法

class Father {
  constructor() {
    this.name = 'father'
  }
  static sayHello() {
    console.log('hello)
  }
}

class Son extends Father {
  constructor() {
    // 不要再调用super之前引用this 否则会跑出ReferenceError
    super() // 相当于super.contructor()
  }
  static sayHello() {
    super.sayHello()
  }
}

Son.sayHello() // hello

ES6 给类构造函数和静态方法添加了内部特性[[HomeObject]],这个特性是一个指针,指向定义该方法的对象。这个指针是自动赋值的而且只能在 Javascript 引擎内部访问。super 始终会定义为[[HomeObject]]的原型

使用super时的注意事项

  • super 只能在派生类构造函数(constructor)和静态方法中使用
  • 不能单独引用super,要么调用构造函数,要么用它引用静态方法
  • 调用super()会调用父类构造函数,并将返回的实例赋值给 this
  • super()的行为如同调用构造函数,如果需要传参则需要手动传入
  • 如果没有定义类构造函数,在实例化派生类时会调用super(),而且会传入所有传给派生类的参数
  • 在类构造函数中,不能在调用super()之前引用 this
  • 如果在派生类中显示定义了构造函数,则要么调用super(),要么在其中返回一个对象
class Father {}

class Son extends Father {
  constructor() {
    // super()
    return {}
  }
}

3.抽象基类

定义:可供其他类继承,但本身不会被实例化 实现:通过new.target,在实例化是检测是不是抽象基类,阻值对抽象基类的实例化 另:通过在抽象基类构造函数中进行检查,可以要求派生类必须定义某个方法。因为原型方法在调用类构造函数之前就已经存在了,所以可以通过 this 来检查

class Father {
  constructor() {
    console.log(new.target)
    if(new.target === Father) {
      throw new Error('Father不能实例化')
    }
    if(!this.foo) {
      throw new Error('继承类必须定义foo()')
    }
  }
}

class Son extneds Father {}

new Son() // Error: 继承类必须定义foo()