JavaScriptにおける extends & super キーワードを用いた継承

概要:このチュートリアルでは、ES6でextendssuperを使用してJavaScriptの継承を実装する方法を学びます。

extends と super を用いた JavaScript の継承の実装

ES6より前は、適切な継承を実装するには複数の手順が必要でした。最も一般的に使用された戦略の1つは、プロトタイプ継承です。

次の例は、プロトタイプ継承の手法を用いて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では、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 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では、Array、String、MapSetなどの組み込み型を継承によって拡張できます。

次の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キーワードを使用して、子クラスのメソッドで親クラスのメソッドを呼び出します。
このチュートリアルは役に立ちましたか?