当前位置:嗨网首页>书籍在线阅读

11-继承

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

9.2.6 继承

在分析原型的时候,已经看到了继承的身影:当创建一个类的实例时,它继承了类原型中所有的功能。尽管如此,它并没有就此打住:如果一个方法没有在对象原型中找到其定义,它会检查原型的原型。这样就建立了一个原型链。JavaScript会沿着原型链走下去,直到某个原型满足了需求。如果找不到这样的原型,程序最终会报错。

原型链最大的好处是能够建立类的层次结构。前面已经讨论了汽车如何归属于一种交通工具。原型链允许将功能置于最合适的继承层次上。例如,汽车可能有个方法叫 deployAirbags ,可以将它当做一般的交通工具方法,但是,大家坐过配备安全气囊的船吗?另一方面,几乎所有的交通工具都可以搭载乘客,所以交通工具都可能有 addPassenger 的方法(可以在超载时抛出异常)。下面看看如何在JavaScript中实现这种场景:

class Vehicle {
   constructor() {
      this.passengers = [];
      console.log("Vehicle created");
   }
   addPassenger(p) {
      this.passengers.push(p);
   }
}
class Car extends Vehicle {
   constructor() {
      super();
      console.log("Car created");
   }
   deployAirbags() {
      console.log("BWOOSH!");
   }
} 

上面这段代码中,第一次出现了 extends 关键字,这个语法标志着 CarVehicle 的子类。其次 super() 也是之前没有见过的。在JavaScript中,super是一个特殊的函数,它调用了父类的构造器。子类必须调用这个方法,否则会报错。

看看下面这个例子:

const v = new Vehicle();
v.addPassenger("Frank");
v.addPassenger("Judy");
v.passengers;                             // ["Frank", "Judy"]
const c = new Car();
c.addPassenger("Alice");
c.addPassenger("Cameron");
c.passengers;                             // ["Alice", "Cameron"]
v.deployAirbags();                        // 报错
c.deployAirbags();                        // "BWOOSH!"

注意,可以在 c 上调用 deployAirbags ,但是不能在 v 上调用。换言之,继承是单向的。 Car 类的实例可以访问所有 Vehicle 类的方法,反之却不行。