Riactを覚えるに当たって、classの習得は必需だったので、殴り書きしていたメモをまとめました。
かなり基礎的なまとめになっているので、JS初心者の方、classの実装未経験の方向けの記事になっていると思います。
##Classの概要
オブジェクト指向 と呼ばれるプログラミング言語についての概念がある。
オブジェクト指向とは プログラムを現実のモノのように構成する 指向 のこと。
classはモノの説明書のこと。メリットはわかりやすくするため。
オブジェクトに関してはこの記事がわかりやすい。
C++,C#やjavaなどの言語ではクラスタイプベースのオブジェクト指向と呼ばれclass機能が備わっているが、かつてのJSはプロトタイプベースのオブジェクト指向なjsにはないので、頑張って似せようとしてきた。
プロトタイプはオブジェクトの元となるオブジェトで、ただの見せかけであり、厳密にいうとクラスではない。
このプロトタイプをさらにわかりやすく書ける構文をclass構文という。
大掛かりな開発では可読性、保守性のため、クラスベースで書くのが一般的のようです。
###いままで(ES5)のオブジェクト指向を意識した構文
厳密にいうとclassではないですが、なるべくclassライクな書き方をしたものです。
var Squea = function(width,height,color){
this.width = width; this.height = height; this.color = color;
}//コンストラクタ
Squea.prototype.squeaCompute = function(){
console.log(this.width * this.height);
}
Squea.prototype.squeaColor = function(){
console.log(this.color);
}//メゾット
var a = new Squea(100,400,"赤");//インスタンス
a.squeaCompute(); //40000
a.squeaColor(); //赤
classをつくるぞというときは、classの名前の頭文字は大文字にすることが一般的(Pascal記法)
クラスからオブジェクト(インスタンス)を生成するイメージ。
クラスは定義、設計図、型枠のイメージで、オブジェクト(インスタンス)は実体。
コンストラクタはオブジェクトで利用するプロパティを準備するために利用するメゾット。
prototype、newプロパティによって、メゾット内のthisでsqueaコンストラクタと紐づく。
これがないと正常にプログラムが動かないので注意すべきところ。
しかしこの書き方だと、コンストラクタとメソッドの定義が分離されているため、クラスとしてまとまりがなく分かりづらく感じる。
###ES6からのClass構文
ES6から、上記の構文をわかりやすくまとめる書き方が採用された。
これがクラス構文。
class Squea { constructor(width, height, color) {
this.width = width; this.height = height; this.color = color;
}
squeaCompute() {
console.log(this.width * this.height);
}
squeaColor() {
console.log(this.color); }
}
let a = new Squea(100,400,"赤");
let b = new Squea(400,900,"青");
a.squeaCompute(); //40000
a.squeaColor(); //赤
b.squeaColor(); //青
コンストラクタとメゾットが同じ{}で括られていて、可動性が高くなった。
ただしこのClassの概念は糖衣構文といって見せかけの構文に過ぎないようです。
これから書き方について詳しく説明していきます。
##class構文の書き方
###クラスの生成
クラスというのはオブジェクトを効率よくオブジェクトを作成していくための「設計図」です。
class Person{}
const a= new Person();
console.log(a);//Person {}
現在Nameクラスには中身がないが、new演算子によってインスタンスが生成されました。
####リテラルでも表記できる
const Person = class{}
これにより、関数リテラルと同じ表現の仕方ができる。
###プロパティを使用するためのコンストラクター
中身が空では何もできないのでプロパティを追加していきます。
そのために必要なのがコンストラクターです。
class Person{
constructor(name,age,from){
this.name = name;
this.age = age;
this.from = from;
}
}
const a = new Person('ben',25,'ibaraki');
const b = new Person('bob',38,'chaina');
console.log(a.name); //ben
console.log(b.name); //bob
プロパティは下記で定義できます。
this.property = value;
####thisについて
コンストラクター配下のthisはクラスが生成したインスタンスで、自分自身を表します。
####インスタンスの生成
設計図(class)から実際にオブジェクトを生成します。
クラスからオブジェクトを生成するには、「new クラス名()」。
それをインスタンスと呼びます。
インスタンスに入れた引数は、コンストラクタで定義した引数順にプロパティとして代入さてていきます。
####呼び出し
呼び出し方は
『インスタンスを入れた変数名.呼び出したいプロパティ』で呼び出せます。
普段使ってるオブジェクトと扱い方が似ています。
###メゾットを定義したい
class Person {
constructor(name, age, from) {
this.name = name;
this.age = age;
this.from = from;
}
//メゾットの定義
toString() {
console.log(`${this.name}は${this.age}才です。`);
}
}
const a = new Person("ben", 25, "ibaraki");
console.log(a.toString());
//benは25才です。
メゾットはクラス内に記述することで、「this.~」で準備しているプロパティにアクセスできる。
呼び出しは、「インスタンスを代入した変数.メゾット」。
もちろん、引数を持たせることができる。
class Person {
//コンストラクタは中略
toString(who = "") {
console.log(`${who}${this.name}は${this.age}才と言う`);
}
}
const a = new Person("ben", 25, "ibaraki");
console.log(a.toString("bobに"));
//bobにbenは25才と言う
###読み込みのみ、または、書き込みのみのプロパティを作成
getter/setterを使います。
getter/setterでは定義の際、クラス内部からしか呼び出せない「※プライベート変数」を使う。
これをしないとエラー(Maximum call stack size exceeded)が起きる
※「_name」のこと
####定義の仕方
class Person {
constructor(name, age, from) {
this.name = name;
this.age = age;
this.from = from;
}
get name() {
return this._name;
}
set name(value) {
this._name = value;
}
}
const a = new Person("ben", 25, "ibaraki");
console.log(a.name);//ben
a.name = "bob";
console.log(a.name);//bob
####getter,setterのメリット
- 読み込みのみ、または、書き込みのみのプロパティを作れる。
- 読み込み時、または、書き込み時に追加の操作を行える。例えば、読み込み回数をカウントするなど。
- 他のプロパティから自動生成される値の場合は、必要になるまでその自動生成の計算を遅延できる。
- プロパティの読み込みや書き込みについて、全く異なる処理に書き換えできる。(このような動作は非推奨)
####setterのみ指定
class Person {
//constructorは中略
set from(value) {
this._from = value;
}
}
const a = new Person("ben", 25, "ibaraki");
console.log(a.from);//undefined
a.from = "usa";
console.log(a.from);//undefined
書き込みことはできても、呼び出し(読み込み)はできない。
####getterのみ指定
class Person {
constructor(name, age, from) {
this.name = name;
this.age = age;
this.from = from;
}
get from() {
return this._from;
}
}
const a = new Person("ben", 25, "ibaraki");
console.log(a.from);//エラー;Cannot set property from of #<Person> which has only a getter
『this.from = from;』が書き込んでいることになるので、エラーが起きる。
『this.from = from;』を消すと下記になる。
class Person {
constructor(name, age, from) {
this.name = name;
this.age = age;
}
get from() {
return this._from;
}
}
const a = new Person("ben", 25, "ibaraki");
console.log(a.name);//ben
console.log(a.from);//undefined
動的なアプリでないとイメージしにくいですが、このようにgetterのみなら、読み取り専用、setterのみなら書き込み専用のプロパティになります。
##振り返り
普段JQueryを使って小規模、中規模のサイト作成をしている私にとってはclassは難しすぎました。業務に出番がない&classで書くほどの規模でないので想像しにくい部分があったからです。
とにかくアプリを作りまくるしかないと思いました。
getter/setterの部分に関してはまとめましたが、理解しきれない部分があるのでダメ出しをお待ちしております。
読んでいただいてありがとうございました。