这是我参与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() 函数就要传参数。