#JS学習シリーズの目的
このシリーズは、私ジャックが学んだJavaScriptのメカニズムについてアウトプットも兼ねて
皆さんと知識や理解を共有するためのものです。
(理解に間違いがあればご指摘いただけると幸いです)
#クラスとは
「コンストラクター関数をクラス表記で書けるようにしたもの」
※このように、既にある機能を簡単に書けるようにしたものをシンタックスシュガーと表現します。
コンストラクター関数については➡【JS学習その⑧】コンストラクター関数 ~prototype・new演算子・instanceof~
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.hello = function() {
console.log('hello ' + this.name);
}
上記のようなコンストラクター関数をクラスに書き換えると次のようになります。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
hello() {
console.log('hello ' + this.name);
}
}
上記のconstructor(){}
関数が、コンストラクターと同じ役割を果たします。
そして、prototype
に格納しているメソッドは、constructor() {}
と同じ並びに追加します。
このように、コンストラクター関数とprototype
で定義するのと、クラスで定義するのは実質同じ意味になります。
クラスの内部で動いているのはprototype
を使った仕組みになるので、クラスはコンストラクター関数のシンタックスシュガーということになります。
const bob = new Person('Bob', 23);
console.log(bob);
インスタンスを生成する際の呼び出し方も同じになります。
#クラス継承とは
「他のクラスのプロパティーとメソッドを継承すること」
まずコンストラクター関数で継承する場合を見てみましょう]
前述したPerson
から新たにJapanese
に継承してみます
//継承元となるPerson
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.hello = function() {
console.log('hello ' + this.name);
}
// 継承先となるJapanese
function Japanese(name, age, gender) {
Person.call(this, name, age); /*Personのプロパティを継承*/
this.gender = gender; /*Japanese独自のプロパティー*/
}
Japanese.prototype = Object.create(Person.prototype); /*Personのprototypeを継承*/
// 継承先のJapanese内で独自のメソッドを作成
Japanese.prototype.hello = function() {
console.log('Konnichiwa ' + this.name);
}
Japanese.prototype.bye = function() {
console.log('Sayonara ' + this.name);
}
const taro = new Japanese('Taro', 23, 'Male');
次にクラスで継承してみます
// 継承元となるPersonクラス
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
hello() {
console.log('hello ' + this.name);
}
}
// 継承先となるJapaneseクラス
class Japanese extends Person {
constructor(name, age, gender) {
super(neme, age); /*Personクラスのプロパティーを継承*/
this.gender = gender;
}
//Japaneseクラス独自のメソッド
hello() {
console.log('Konnichiwa ' + this.name);
}
bye() {
console.log('Sayonara ' + this.name);
}
}
const taro = new Japanese('Taro', 23, 'Male');
taro.bye(); /*Sayonara Taro*/
上記のコードのように、クラス継承では、新たに継承先クラスを作る際にextends
というキーワードで継承元のクラスを指定します。
そして、constructor() {}
関数内でsuper
というキーワードを使い、引数に継承元のconstructor
関数に使用している引数を指定することで、継承元クラスのプロパティーを継承することができます。
注意点としては、継承先クラス(今回の場合はJapanese)で新たにthis
を使ってプロパティーを指定する場合、先にsuper
で継承元のプロパティーを継承してから継承先クラス独自のプロパティーを設定してください。(でないとエラーとなります)
##superとは
「継承元の関数を呼び出すためのキーワード」
前述したように、super
は継承元のプロパティーを継承先に継承できますが、メソッドも継承できます。
// 継承元となるPersonクラス
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
hello() {
console.log('hello ' + this.name);
}
}
// 継承先となるJapaneseクラス
class Japanese extends Person {
constructor(name, age, gender) {
super(neme, age); /*Personクラスのプロパティーを継承*/
this.gender = gender;
}
//Japaneseクラス独自のメソッド
hello() {
super.hello(); /*Personのhelloメソッドを継承*/
console.log('Konnichiwa ' + this.name);
}
bye() {
console.log('Sayonara ' + this.name);
}
}
const taro = new Japanese('Taro', 23, 'Male');
taro.hello(); /*hello Taro*/
/*Konnichiwa Taro*/
基本的にsuper
はクラス内で使用しますが、一部例外的にオブジェクトの中でも呼べます。
const american = {
hello() {
console.log('hello ' + this.name);
}
};
const bob = {
name: 'Bob',
hello() {
super.hello(); /*americanオブジェクトのhelloメソッドを継承*/
console.log('konnichiwa ' + this.name);
}
};
Object.setPrototypeOf(bob, american); /*bobオブジェクトのprototypeにamericanオブジェクトを設定*/
bob.hello(); /*hello Bob*/
/*konnichiwa Bob*/
// 文法エラーとなる書き方
bob.bye = function() {
super.hello();
};
上記のコードのように、
american
オブジェクトをbob
オブジェクトのprototype
にObject.setPrototypeOf
で設定します。
これでamerican
がbob
に継承されたので、bob
オブジェクトのhello
メソッド内でsuper
を使ってamerican
オブジェクトのhello
メソッドを継承します。
そして、bob.hello()
でメソッドを実行するとコメントの内容になります。
ただし、これはオブジェクトリテラルの中でしかsuper
は使えません。
よって、上記のコードの最後に書いているように新たにプロパティーを設けてその中でsuper
を使って継承はできません。(SyntaxError(文法エラー)になります)
#まとめ
いかがでしたでしょうか。
クラスも、コンストラクター関数を理解した後だとさらに理解が深まり、その便利さがよく分かるのではないでしょうか。
今や、クラスはJavaScriptにおいてなくてはならない技術なので、しっかり理解しておきましょう!