JavaScript 类继承使用 extends & super
您将学习如何在 ES6 使用 extends 和 super 实现 JavaScript 继承
在本教程中,您将学习如何在 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
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();
代码是如何运行的。
首先,使用 extends
关键词使 Bird
类继承 Animal
类:
class Bird extends Animal { // ...}
Animal
类称为基类或父类,而 Bird
类称为派生类或子类。通过 extends 关键词,Bird
类继承 Animal
类的所有方法和属性。
其次,在 Bird
的构造函数调用 super()
并使用 legs
参数调用 Animal
的构造函数。
如果子类在有构造函数,JavaScript 在情况下要求调用 super()
。正如您在 Bird
类中看到的,这 super(legs)
等同于 ES5 的以下语句:
Animal.call(this, legs);
如果 Bird
类没有构造函数,则无需执行任何其他操作:
class Bird extends Animal {
fly() {
console.log('flying');
}
}
它等效于以下类声明:
class Bird extends Animal {
constructor(...args) {
super(...args);
}
fly() {
console.log('flying');
}
}
但是,子类有一个构造函数,它需要调用 super()
。例如,以下代码会导致错误:
class Bird extends Animal {
constructor(legs) {
}
fly() {
console.log('flying');
}
}
错误:
ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
因为 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());
影子方法
ES6 允许子类和父类有同名的方法。在这种情况下,当你调用子类对象的方法时,子类中的方法会遮蔽父类的方法。
下面的 Dog
类扩展 Animal
类并重新定义 walk()
方法:
class Dog extends Animal {
constructor() {
super(4);
}
walk() {
console.log(`go walking`);
}
}
let bingo = new Dog();
bingo.walk(); // go walking
要在子类中调用父类的方法,可以这样调用 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
继承静态成员
除了属性和方法外,子类还继承父类的所有静态属性和方法。例如:
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');
}
}
在此示例中,Animal
类有静态方法 helloWorld()
,并且此方法 Bird.helloWorld()
与 Animal.helloWorld()
方法的行为相同:
Bird.helloWorld(); // Hello World
从内置类型继承
JavaScript 允许您通过继承扩展内置类型,例如 Array、 String 、Map 和 Set。
下面 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());
}
结论
- 在 ES6 使用 extends 关键词实现继承。要扩展的类称为基类或父类。扩展基类或父类的类称为派生类或子类。
super(arguments)
在子类的构造函数中调用调用父类的构造函数。- 使用
super
关键词在子类的方法中调用父类的方法。