概要:このチュートリアルでは、ES6でextends
とsuper
を使用してJavaScriptの継承を実装する方法を学びます。
extends と super を用いた JavaScript の継承の実装
ES6より前は、適切な継承を実装するには複数の手順が必要でした。最も一般的に使用された戦略の1つは、プロトタイプ継承です。
次の例は、プロトタイプ継承の手法を用いて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では、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());
}
Code language: JavaScript (javascript)
まとめ
- ES6で継承を実装するには、
extends
キーワードを使用します。拡張されるクラスは、基本クラスまたは親クラスと呼ばれます。基本クラスまたは親クラスを拡張するクラスは、派生クラスまたは子クラスと呼ばれます。 - 子クラスのコンストラクタで
super(arguments)
を呼び出して、親クラスのコンストラクタを呼び出します。 super
キーワードを使用して、子クラスのメソッドで親クラスのメソッドを呼び出します。