你不知道的JS系列上( 44 ) - 多态
class Vehicle { constructor() { this.engines = 1 } ignition () { console.log('Turning on my engine'); } drive () { this.ignition(); console.log('Steering and moving forward!') } } class Car extends Vehicle { constructor() { super() this.wheels = 4 } drive () { super.drive() console.log('Rolling on all ', this.wheels, ' wheels') } } class SpeedBoat extends Vehicle { constructor() { super(); this.engines = 2 } ignition () { console.log('Turning on my ', this.engines, ' engines.'); } pilot() { super.drive() console.log('Speeding through the water with ease!') } }
Car 重写了继承自父类的 drive() 方法,但是之后 Car 调用了 super.drive() 方法,这表明 Car 可以引用继承来的原始 drive() 方法。快艇的 pilot() 方法同样引用了原始 drive() 方法。
这个技术被称为多态或者虚拟多态。在本例中,更恰当的说法是相对多态。之所以说 “相对” 是因为我们并不会定义想要访问的类,而是相对引用 “查找上一层”。在子类中也可以相对引用它继承的父类,这种相对引用通常被称为 super。
多态的另一方面是,在继承链的不同层次中一个方法名可以被多次定义,当调用方法时会自动选择合适的定义
在 pilot() 中通过相对多态引用了父类的 drive(),但是那个 drive() 方法直接通过名字引用了 ignition() 方法。那么语言引擎使用那个 ignition()呢,父类的还是子类的? 实际上会使用子类的,如果你是直接实例化父类,那语言引擎就会使用父类的 ignition() 方法。
换言之,ignition() 方法定义的多态性取决于你是在哪个类的实例中引用它。
子类得到的仅仅是继承自父类行为的一个副本。子类对继承到的一个方法进行重写,不会影响父类中的方法,这两个方法互不影响,因此才能使用相对多态引用访问父类的方法(如果重写会影响父类的方法,那重写之后父类中的原始方法就不存在了,自然无法引用)
多态不表示子类和父类有关联,子类得到只是父类的一份副本,类的继承其实就是复制。