继承是一种在类之间建立父子关系的方式。 子类(有时也称为派生类)可以访问父类(有时也称为基类)定义的行为和数据。
class Pet {
constructor(name) {
this.name = name;
}
introduce() {
console.log(`This is my pet, ${this.name}.`);
}
}
class Dog extends Pet {}
const dog = new Dog('Otis');
dog.introduce();
// => This is my pet, Otis.
子类声明中的extends关键字通过原型链与父类建立联系。
由子类构造函数创建的对象,其原型链中会包含父类的原型,因此可以访问父类定义的任何方法或数据。
const dog = new Dog('Otis');
Dog.prototype.isPrototypeOf(dog); // => true
Pet.prototype.isPrototypeOf(dog); // => true
Pet.prototype.isPrototypeOf(Dog.prototype); // => true
Pet.prototype.hasOwnProperty('introduce'); // => true
Dog.prototype.hasOwnProperty('introduce'); // => false
dog.hasOwnProperty('introduce'); // => false
如果子类没有定义构造函数,就会使用父类的构造函数。
但如果子类定义了自己的构造函数,就必须显式调用父类的构造函数。
要在子类构造函数内部调用父类构造函数,需要使用关键字super。
class Pet {
constructor(name) {
this.name = name;
}
}
class Dog extends Pet {
constructor(name, breed) {
super(name);
this.breed = breed;
}
}
const dog = new Dog('Otis', 'Pug');
由于父类构造函数负责初始化新对象并将其赋值给this,因此必须在子类构造函数使用this之前就调用它。
class Dog extends Pet {
constructor(name, breed) {
// using 'this' before calling the parent constructor with 'super'
this.breed = breed;
super(name);
}
}
const dog = new Dog('Otis', 'Pug');
// => ReferenceError: Must call super constructor in derived class before accessing 'this'...
除了从父类继承的行为之外,子类还可以定义自己的行为。
这是使用继承的主要原因之一:让特定的子类拥有自己独有的数据和方法,同时通过父类提供的共享方法和数据彼此关联。
class Dog extends Pet {
constructor(name, breed) {
super(name);
this.breed = breed;
}
describe() {
console.log(`${this.name} is a ${this.breed}.`);
}
}
const dog = new Dog('Otis', 'Pug');
dog.introduce();
dog.describe();
// => 'This is my pet, Otis.'
// => 'Otis is a Pug.'
子类还可以重写父类定义的方法的行为,用子类定义的行为来替换或扩展它。
class Cat extends Pet {
// replacing parent class behavior
introduce() {
console.log(`This is my cat, ${this.name}.`);
}
}
class Dog extends Pet {
constructor(name, breed) {
super(name);
this.breed = breed;
}
describe() {
console.log(`${this.name} is a ${this.breed}.`);
}
// extending parent class behavior
introduce() {
super.introduce();
this.describe();
}
}
const cat = new Cat('Milo');
cat.introduce();
// => 'This is my cat, Milo.'
const dog = new Dog('Otis', 'Pug');
dog.introduce();
// => This is my pet, Otis.
// => Otis is a Pug.
如果要在子类中同名方法的方法体里调用父类定义的方法,必须使用关键字super来引用父类。