2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【JS学習その⑨】JavaScriptにおけるクラスとその継承

Posted at

#JS学習シリーズの目的
このシリーズは、私ジャックが学んだJavaScriptのメカニズムについてアウトプットも兼ねて
皆さんと知識や理解を共有するためのものです。
(理解に間違いがあればご指摘いただけると幸いです)

#クラスとは
コンストラクター関数をクラス表記で書けるようにしたもの
※このように、既にある機能を簡単に書けるようにしたものをシンタックスシュガーと表現します。
コンストラクター関数については➡【JS学習その⑧】コンストラクター関数 ~prototype・new演算子・instanceof~

main.js
function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.hello = function() {
    console.log('hello ' + this.name);
}

上記のようなコンストラクター関数をクラスに書き換えると次のようになります。

main.js
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    hello() {
        console.log('hello ' + this.name);
    }
}

上記のconstructor(){}関数が、コンストラクターと同じ役割を果たします。
そして、prototypeに格納しているメソッドは、constructor() {}と同じ並びに追加します。
このように、コンストラクター関数とprototypeで定義するのと、クラスで定義するのは実質同じ意味になります。
クラスの内部で動いているのはprototypeを使った仕組みになるので、クラスはコンストラクター関数のシンタックスシュガーということになります。

main.js
const bob = new Person('Bob', 23);
console.log(bob);

インスタンスを生成する際の呼び出し方も同じになります。

#クラス継承とは
他のクラスのプロパティーとメソッドを継承すること

まずコンストラクター関数で継承する場合を見てみましょう]
前述したPersonから新たにJapaneseに継承してみます

main.js
//継承元となる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');

次にクラスで継承してみます

main.js
// 継承元となる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は継承元のプロパティーを継承先に継承できますが、メソッドも継承できます。

main.js
// 継承元となる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はクラス内で使用しますが、一部例外的にオブジェクトの中でも呼べます。

main.js
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オブジェクトのprototypeObject.setPrototypeOfで設定します。
これでamericanbobに継承されたので、bobオブジェクトのhelloメソッド内でsuperを使ってamericanオブジェクトのhelloメソッドを継承します。
そして、bob.hello()でメソッドを実行するとコメントの内容になります。
ただし、これはオブジェクトリテラルの中でしかsuperは使えません
よって、上記のコードの最後に書いているように新たにプロパティーを設けてその中でsuperを使って継承はできません。(SyntaxError(文法エラー)になります)

#まとめ
いかがでしたでしょうか。
クラスも、コンストラクター関数を理解した後だとさらに理解が深まり、その便利さがよく分かるのではないでしょうか。
今や、クラスはJavaScriptにおいてなくてはならない技術なので、しっかり理解しておきましょう!

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?