摘要: 在本教程中,您将学习如何使用 ES6 中的 extends
和 super
来实现 JavaScript 继承。
使用 extends 和 super 实现 JavaScript 继承
在 ES6 之前,实现正确的继承需要多个步骤。其中最常用的策略是 原型继承。
以下演示了如何使用原型继承技术使 Bird
从 Animal
继承属性
function Animal(legs) {
this.legs = legs;
}
Animal.prototype.walk = function() {
console.log('walking on ' + this.legs + ' legs');
}
function Bird(legs) {
Animal.call(this, legs);
}
Bird.prototype = Object.create(Animal.prototype);
Bird.prototype.constructor = Animal;
Bird.prototype.fly = function() {
console.log('flying');
}
var pigeon = new Bird(2);
pigeon.walk(); // walking on 2 legs
pigeon.fly(); // flying
Code language: JavaScript (javascript)
ES6 通过使用 extends
和 super
关键字简化了这些步骤。
以下示例定义了 Animal
和 Bird
类,并通过 extends
和 super
关键字建立继承关系。
class Animal {
constructor(legs) {
this.legs = legs;
}
walk() {
console.log('walking on ' + this.legs + ' legs');
}
}
class Bird extends Animal {
constructor(legs) {
super(legs);
}
fly() {
console.log('flying');
}
}
let bird = new Bird(2);
bird.walk();
bird.fly();
Code language: JavaScript (javascript)
它是如何工作的。
首先,使用 extends
关键字使 Bird
类继承自 Animal
类
class Bird extends Animal {
// ...
}
Code language: JavaScript (javascript)
Animal
类被称为 基类 或 父类,而 Bird
类被称为 派生类 或 子类。通过这样做,Bird
类继承了 Animal
类所有的方法和属性。
其次,在 Bird
的构造函数中,调用 super()
来用 legs
参数调用 Animal
的构造函数。
JavaScript 要求子类在有构造函数的情况下调用 super()
。正如您在 Bird
类中所看到的,super(legs)
等同于 ES5 中的以下语句
Animal.call(this, legs);
Code language: JavaScript (javascript)
如果 Bird
类没有构造函数,则无需执行任何其他操作
class Bird extends Animal {
fly() {
console.log('flying');
}
}
Code language: JavaScript (javascript)
它等同于以下类
class Bird extends Animal {
constructor(...args) {
super(...args);
}
fly() {
console.log('flying');
}
}
Code language: JavaScript (javascript)
但是,子类有构造函数,它需要调用 super()
。例如,以下代码会导致错误
class Bird extends Animal {
constructor(legs) {
}
fly() {
console.log('flying');
}
}
Code language: JavaScript (javascript)
错误
ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
Code language: JavaScript (javascript)
由于 super()
初始化了 this
对象,因此您需要在访问 this
对象之前调用 super()
。尝试在调用 super()
之前访问 this
也会导致错误。
例如,如果您想初始化 Bird
类的 color
属性,您可以按照以下方法进行
class Bird extends Animal {
constructor(legs, color) {
super(legs);
this.color = color;
}
fly() {
console.log("flying");
}
getColor() {
return this.color;
}
}
let pegion = new Bird(2, "white");
console.log(pegion.getColor());
Code language: JavaScript (javascript)
隐藏方法
ES6 允许子类和父类具有相同名称的方法。在这种情况下,当您调用子类对象的某个方法时,子类中的方法将隐藏父类中的方法。
以下 Dog
类扩展了 Animal
类并重新定义了 walk()
方法
class Dog extends Animal {
constructor() {
super(4);
}
walk() {
console.log(`go walking`);
}
}
let bingo = new Dog();
bingo.walk(); // go walking
Code language: JavaScript (javascript)
要在子类中调用父类的方法,您可以使用 super.method(arguments)
,如下所示
class Dog extends Animal {
constructor() {
super(4);
}
walk() {
super.walk();
console.log(`go walking`);
}
}
let bingo = new Dog();
bingo.walk();
// walking on 4 legs
// go walking
Code language: JavaScript (javascript)
继承静态成员
除了属性和方法之外,子类还继承了父类所有的静态属性和方法。例如
class Animal {
constructor(legs) {
this.legs = legs;
}
walk() {
console.log('walking on ' + this.legs + ' legs');
}
static helloWorld() {
console.log('Hello World');
}
}
class Bird extends Animal {
fly() {
console.log('flying');
}
}
Code language: JavaScript (javascript)
在此示例中,Animal
类具有 helloWorld()
静态方法,此方法可作为 Bird.helloWorld()
使用,并与 Animal.helloWorld()
方法的行为相同
Bird.helloWorld(); // Hello World
Code language: JavaScript (javascript)
从内置类型继承
JavaScript 允许您通过继承扩展内置类型,如 数组、字符串、映射 和 集合。
以下 Queue
类扩展了 Array
引用类型。语法比使用 Queue
实现的 构造函数/原型模式 更简洁。
class Queue extends Array {
enqueue(e) {
super.push(e);
}
dequeue() {
return super.shift();
}
peek() {
return !this.empty() ? this[0] : undefined;
}
empty() {
return this.length === 0;
}
}
var customers = new Queue();
customers.enqueue('A');
customers.enqueue('B');
customers.enqueue('C');
while (!customers.empty()) {
console.log(customers.dequeue());
}
Code language: JavaScript (javascript)
摘要
- 使用
extends
关键字在 ES6 中实现继承。要扩展的类称为基类或父类。扩展基类或父类的类称为派生类或子类。 - 在子类的构造函数中调用
super(arguments)
来调用父类的构造函数。 - 使用
super
关键字在子类方法中调用父类方法。