ES6 Class 之继承类

410 阅读3分钟

这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

假设有一个 Animal 类,现在想要定义一个 Dog 类,这个 Dog 类要继承 Animal 类。那么该怎么做呢?

1. ES5 中继承类

我们前面在ES6 Class 之类的声明》一文中讲过,ES5 中,声明类的函数就是类的构造函数,至少这个函数起到了构造函数的作用。现在我们想继承 Animal 这个父类,就需要在声明子类 Dog 类的这个函数中先运行一遍 Animal 的构造函数,并且把实例对象的指针指向当前的 Dog 类。

/* ES5 中有很多继承方法,这里只举一个 */
let Animal = function (type) {
  this.type = type
}
Animal.prototype.eat = function () {
  Animal.walk()
  console.log('I am eating food.')
}
Animal.walk = function () {
  console.log('I am walking.')
}

// 定义子类 Dog,并继承父类 Animal 构造函数中的属性和方法
let Dog = function () {
  // 初始化父类的构造函数(下面 call 方法的作用是将 Animal 类中的 this 指向到当前类(Dog 类)的实例对象上去,
  // 这就能让父类的(构造函数中的)属性和方法挂载到当前的实例对象上,也就实现了“一部分”继承(只继承了父类构造函数中的属性和方法,未继承父类原型链上的属性和方法);
  // 后面的 'dog' 是父类构造函数需要传的参数)
  Animal.call(this, 'dog')
  // 给 Dog 类的实例对象挂载 run 方法
  this.run = function () {
    console.log('I can run.')
  }
}
// 子类继承父类的原型链,prototype 是对象,是引用类型,这边赋的是地址值
Dog.prototype = Animal.prototype

let dog = new Dog()
dog.eat()

/* 运行结果:
I am walking.
I am eating food.
*/

可以看到,用这种方式实现继承需要做两步操作:一是初始化父类的构造函数,二是改变子类的原型链指向。

好像有点小麻烦......那 ES6 中继承一个类是不是会简单点呢?我们往下看。

2. ES6 中继承类

ES6 的继承很简单,用一个单词(extends)就能实现啦。

/* ES6 中继承一个类 */
class Animal {
  constructor (type) {
    this.type = type
  }
  // 定义实例对象的方法
  eat () {
    Animal.walk() // 调用静态方法 walk(),静态方法就是属于类的,调用时要用类名调用
    console.log('I am eating food...')
  }
  // 定义类的静态方法
  static walk () {
    console.log('walk walk')
  }
}

// 声明 Dog 类,同时继承 Animal 类
class Dog extends Animal {
  // 编写构造函数
  constructor (type) {
    super(type)
    this.age = 2
  }
}

let dog = new Dog('dog')
dog.eat()
console.log(dog)

/* 运行结果:
walk walk
I am eating food...
Dog {type: "dog", age: 2}
*/

上面的代码在声明 Dog 类时,如果构造函数中只需继承父类的构造函数,即没有 this.age = 2 这行代码时,这块代码也可以省略不写,即下面这块代码可以省略不写:

constructor (type) {
  super(type)
}

另外,父类的构造函数中如果需要传参数,子类那边继承父类的构造函数时也要传参数,也就是 super() 函数也要传参数,就像上面传了个 type 进来,你甚至可以写成这样:

constructor () {
  super('panda')
}

总之,父类的构造函数中如果需要传参数,子类那边的 super() 函数就要传参数。