BETA

JavaScriptでclass構文を使う際の簡単なまとめ

投稿日:2019-02-23
最終更新:2019-02-26

偉大な先人達によるオブジェクト指向プログラミング(以下:OOP)についての解説が
ネットに複数あり、感謝をしながら理解を深めています。
そんな参考になる解説出てきた単語を自分が分かりやすいように簡単にまとめました。
詳細についてはコードを書きながら理解が十分できたと判断したら記事にしようと思います。

ES2015よりclass構文が追加されてOOPを簡潔に書けるようになりました。
チームでの開発や運用保守をする際に戸惑わないように読み書きが
できるようにしておいた方がいいと思います。
また、OOPの概念は他のメジャーなプログラミング言語でも利用されているので
知っておくと将来役に立つかもしれません。

クラス構文で使う単語

  • class
  • インスタンス
  • constructor(コンストラクタ)
  • インスタンスメソッド
  • staticメソッド(静的メソッド)
  • 継承
  • super
  • オーバーライド
  • getterとsetter

class

プロトタイプ(雛形)を作成するためのキーワードです。
classキーワードを使って定義をするとテンプレートとなるオブジェクトを作成する
ことができます。
定義の方法は2種類あります。

  • クラス宣言文
  • クラス式

クラス宣言文

クラス宣言文はclassキーワードを使ってclass クラス名{ }のように定義します。

class kurasuSengen { }; // class クラス名

クラス式

クラスを値として定義して変数に代入します。
クラス式ではクラス名を省略することができます。

const kurasuSiki = class kurasuSiki {}; //クラスを値として変数に代入  

const kurasuSiki = class {}; //クラス名の省略

インスタンス

classキーワードで定義したオブジェクト(プロトタイプ)をベースに
作成したオブジェクトのこと
をインスタンスと呼びます。
単語の意味は「実体」や「実例」などと言われています。
インスタンスはnewキーワードを使って作成します。
このインスタンスを作成することをインスタンス化と呼びます。
instanceof演算子を使えばベースとなったプロトタイプを判定することもできます。

class Person {  

};  
// class宣言文で定義したPersonをインスタンス化  
const tarou = new Person();  
// プロトタイプ Personは使い回せる  
const hanako = new Person();  

//同じプロトタイプを元に作成されたが上記の2つは異なるインスタンス  
console.log(tarou === hanako); // => false  

//ベースとなったプロトタイプを判定するにはinstanceofを使う  
console.log(tarou instanceof Person); // => true

constructor(コンストラクタ)

クラス内で使われる特殊なメソッドです。
インスタンス化の際に必ず実行されるメソッドで、
この中に新しく作成されるインスタンスオブジェクトの初期化処理などを記述していきます。
初期化処理はnew演算子にセットした引数がコンストラクタの仮引数に渡されて、
インスタンスオブジェクト(this)へ代入されます。
不要な場合は省略することもでき、その場合は空のコンストラクが自動的に定義されます。

class kurasuSengen {  
 // コンストラクタ関数の仮引数として`x`と`y`を定義  
    constructor(x, y) {  
        // コンストラクタ関数における`this`はインスタンスを示すオブジェクト  
        // インスタンスの`x`と`y`プロパティにそれぞれ値を設定する  
        this.x = x;  
        this.y = y;  
    }  
}   

const kurasuSiki = class { //コストラクタの処理が必要ない場合は省略できる  

}  
//new演算子でインスタンスを作成してプロトタイプのコンストラクタの仮引数に引数を渡す  
const instance = new kurasuSengen(1, 2);  
console.log(instance.x); // 1  
console.log(instance.y); // 2

インスタンスメソッド

クラスにメソッドを定義したものをインスタンスメソッドと呼びます。
定義したメソッドの中からインスタンスを参照するにはthisを使用します。

class クラス {  
    メソッド() {  
        // ここでの`this`はベースオブジェクトを参照  
    }  
}  

const インスタンス = new クラス();  
// メソッド呼び出しのベースオブジェクト(`this`)は`インスタンス`となる  
インスタンス.メソッド();

インスタンスメソッドはオブジェクトのメソッド定義の書き方はできないので注意

// クラスでは次のようにメソッドを定義できない  
class クラス {  
   // SyntaxError  
   メソッド: () => {}  
   // SyntaxError  
   メソッド: function(){}  
}

staticメソッド(静的メソッド)

クラスをインスタンス化せずに利用できるメソッドをstaticメソッドと呼びます。
クラス経由で実行されるのでインスタンスの状態(値)を利用できません。
staticメソッドの定義方法はメソッド名の前にstaticとつけます。
実行方法はクラス名.staticメソッド名()で実行できます。

class クラス {  
    static メソッド() {  
    }  
}  
// staticメソッドの呼び出し  
クラス.メソッド();

継承

既存のクラスの特性(プロパティやメソッド)を引き継いだ新しいクラスを定義することを
継承といいます。
extendsキーワードを使って継承元となる親クラスを指定することで特性を引き継いだ新しい
クラス(子クラス)を定義できます。

class 子クラス extends 親クラス {  

}

継承をすることによって重複したコードを減らすことができます。
ただし、継承は親クラスの改変の影響を多大に受けます。
親クラスがメソッドの削除や修正をした場合に子クラスもその改変を追従します。
なので継承は明確に上下関係が存在する場合のみに利用をした方がいいです。

super

extendsを使って定義した子クラスに継承元の親クラスのメソッドを呼び出す
ために必要なキーワードです。
コンストラク内とそれ以外のメソッドでは使い方が違うので注意が必要です。
コンストラクタ内ではsuperのみで実行可能・・・①
メソッドではsuper.メソッド名で実行・・・・・・②

オーバーライド

extendsを使って継承した子クラスで親クラスのメソッドと同じ名前で定義すると
そのメソッドを上書きすることができます。これをオーバーライドと呼びます。
オーバーライド前の親クラスのメソッドを呼ぶには子クラスでsuperを使用すれば
呼び出すことができます。

class Animal {  
  constructor(name) {  
    console.log('親クラスのコンストラクタ');  
    this.name = name;  
  }  
  speak() {  
    console.log('親クラスのspeakメソッド');  
  }  
}  

class Dog extends Animal {  
  constructor(name, age) {  
    console.log('子クラスのコンストラクタ');  
    super(name); // ①  
    this.age = age;  
  }  
  speak() { //オーバーライド  
    super.speak();// ②  
    console.log('子クラスのspeakメソッド');  
  }  
}  
const dog = new Dog('ポチ', 1);  
dog.speak();  
console.log('名前: ' + dog.name + '年齢: ' + dog.age);

getterとsetter

クラスに対してメソッドを定義できますが、メソッドはメソッド名()のように呼び出す必要があります。 クラスでは、プロパティの参照(getter)、プロパティへの代入(setter)時に呼び出される特殊なメソッドを定義できます。 このメソッドはプロパティのように振る舞うためアクセッサプロパティと呼ばれます。
js-primer アクセッサプロパティ

getterはget、setterはsetをメソッドの前につけることによって
メソッドをプロパティ名で呼ぶことができるようになります。
getterは仮引数はありませんが、必ず値を返す必要があります。
setterは仮引数にはプロパティに代入された値が入りますが、
値を返す必要はありません。

class クラス {  
    // getter  
    get プロパティ名() { getterとはget構文を  
        return 値;  
    }  
    // setter  
    set プロパティ名(仮引数) {  
        // setterの処理  
    }  
}  
const インスタンス = new クラス();  
インスタンス.プロパティ名; // getterが呼び出される  
インスタンス.プロパティ名 = 値; // setterが呼び出される

getterとsetterの使い所

なぜわざわざメソッド名にgetやらsetをつけてプロパティのように
扱うのでしょうか?
これには複数の理由があり、OOPとJavaScriptの理解が必要になってきます。
私も全ての理由を説明できません。。
調べた中で一番多いのはgetterとsetterを使うことによって
オブジェクトのプロパティを直接操作しづらくするというものでした。

class Item {  
  constructor(name, priceYen) {  
    // プロパティ名の先頭にアンダースコアをつける。  
    // 強制力はないが、「直に触るな」という暗黙の了解がある。  
    this._name = name;  
    this._priceYen = priceYen;  
  }  
  // getterを通してプロパティにアクセスする  
  get name() {  
    return this._name;  
  }  
  get priceYen() {  
    return this._priceYen;  
  }  
}  

const item = new Item('USB Cable', 200);  

// 書き換えようとしてもできない  
item.priceYen = 100;//TypeError: Cannot set property name of #<Item> which has only a getter  
item.name = 'HDMI Cable';//TypeError: Cannot set property name of #<Item> which has only a getter  
item._name = "HDMI" //これは書き換えができてしまう_プロパティ名は直に触ってはいけない  
item //{"_name":"HDMI","_priceYen":200}

getterとsetterを通してプロパティの値を参照・書き換えを行うことでアクセス制限をすることができます。

まとめ

実際にはOPPを使う為に知らないといけない単語や挙動は
まだたくさんあります
カプセル化にポリモーフィズムなど盛りだくさんです。
基本をさらっと理解しておき、コードを書く→調べるを繰り返して
知識を体で覚えていったほうがいいと思います。
ここが違うというのがありましたらぜひコメントください!!

参考URL

web白熱教室 オブジェクト指向とは
Subterranean Flower Blog JavaScriptで気楽に始めるオブジェクト指向プログラミング
js-primer クラス
MDN クラス

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

@tomorebの技術ブログ

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
or 外部アカウントではじめる
10秒で技術ブログが作れます!