使用 extends 和 super 实现 JavaScript 继承

摘要: 在本教程中,您将学习如何使用 ES6 中的 extendssuper 来实现 JavaScript 继承。

使用 extends 和 super 实现 JavaScript 继承

在 ES6 之前,实现正确的继承需要多个步骤。其中最常用的策略是 原型继承

以下演示了如何使用原型继承技术使 BirdAnimal 继承属性

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 通过使用 extendssuper 关键字简化了这些步骤。

以下示例定义了 AnimalBird 类,并通过 extendssuper 关键字建立继承关系。

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 constructorCode 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 walkingCode 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 walkingCode 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 WorldCode 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 关键字在子类方法中调用父类方法。
本教程对您有帮助吗?