[TypeScript] Class


#####オブジェクト指向プログラミング（object-oriented programming）（OOP）
現実世界の物に見立ててプログラムする方法
どのようにアプリケーションを作るかという方法の一つ
人間にとってわかりやすくロジックを分割する方法の一つ

#####オブジェクト
作る方法
・オブジェクトリテラル
・Class

#####Class
・オブジェクトの設計図
・Classから作られたオブジェクトはインスタンスと呼ばれる
・似たようなオブジェクトを複数作成する際に便利

#####constructor関数
↓Personというclassを元に、オブジェクトを作成するときに実行される関数

```class.ts
class Person {
  name: string;
  constructor() {
    
  }
}
```

↓newで初期化したときに`initName: string`を受け取っている。

```class.ts
class Person {
  name: string;
  constructor(initName: string) {
    this.name = initName;
  }
}

const quill = new Person('Quill');
console.log(quill);
```
↓console.log(quill);の結果
[![Image from Gyazo](https://i.gyazo.com/0a665f34c30ddb431c8cd71aa5d7c88b.png)](https://gyazo.com/0a665f34c30ddb431c8cd71aa5d7c88b)

#classにメソッドを追加する
thisを使います。

```class.ts
  greeting() {
    console.log(`Hello! My name is ${this.name}`);
  }
```

#classを型として使う
↓thisの型に、classとして設定したPersonを指定することができます。
↓classのPersonを作ると同時に、型のPersonも作られているからです。

```class.ts
class Person {

  name: string;

  constructor(initName: string) {
    this.name = initName;
  }

  greeting(this: Person) {
    console.log(`Hello! My name is ${this.name}`);
  }
}

```

つまり、TypeScriptのclassを作るということは、
オブジェクトを作る設計図を作る機能以外に、そのclassが作り出すインスタンスを、
表す型も同時に作っているということになります。

#private修飾子とpublic修飾子
######private修飾子
↓のように使い、class外ではageにアクセスすることができません。

```class.ts
class Person {

  name: string;
  private age:number;
```

#####public修飾子
class内でも、外でもどこでも使えます。

```class.ts
class Person {

  name: string;
  private age:number;
```

↑はnameがデフォルトでpublicになっていますが、
↓のように明示的に書いても良いです。

```class.ts
class Person {

  public name: string;
  private age:number;
```

#初期化処理を省略する方法
↓これを

```class.ts
class Person {

  name: string;
  private age:number;

  constructor(initName: string, initAge: number;) {
    this.name = initName;
    this.age = initAge;
  }
```

↓こうします。

```class.ts
class Person {
  constructor(public name: string, private age: number;) {
  }
```

fieldの先頭にpublicもしくはprivateをつければ完了です。

#readonly修飾子
readonlyをつけると、
class内でも、外でも、読むだけ！というものです。

```class.ts
class Person {
  constructor(public readonly name: string, private readonly age: number;) {
  }
```

そうそう変わらないもの、
例えば「名前」や「マイナンバー」なんかに使ったりします。

#extends
↓class Teacherは、class Personの派生のようなものですね。　Personのメソッドを使いたい。
↓そんなときに同じコードを改めて書くのは非効率です。

```class.ts
class Person {
  constructor(public readonly name: string, private readonly age: number;) {
  }

  incrementAge() {
  }

  greeting(this: Person) {
    console.log(`Hello! My name is ${this.name}. I am ${this.age} years old.`);
  }
}

class Teacher {
  
}
```

↓そんなときはextendsを使って、class継承をします。

```class.ts
class Person {
  constructor(public readonly name: string, private readonly age: number;) {
  }

  incrementAge() {
  }

  greeting(this: Person) {
    console.log(`Hello! My name is ${this.name}. I am ${this.age} years old.`);
  }
}

class Teacher extends Person {

}
```

これでclass Personと同じ機能がそのままclass Teacherで使えるようになりました。

じゃあ、class Teacherにconstructer関数に機能を付け加えたい場合どうするか？
↓こうします。

```class.ts
class Person {
  constructor(public readonly name: string, private readonly age: number;) {
  }

  incrementAge() {
  }

  greeting(this: Person) {
    console.log(`Hello! My name is ${this.name}. I am ${this.age} years old.`);
  }
}

class Teacher extends Person {
  constructor(name: string, age: number, public subject: string) {
    super(name, age);
  }
}
```
派生されたclassのconstracterは、superを含む必要があります。
+@で付け加えるものには、
改めてpublic subject: stringのようにpublicかprivateを指定する必要があります。

↓もし greetingに文章を付け加えたいと思ったら、上書きするしかありません。

```class.ts
class Person {
  constructor(public readonly name: string, private readonly age: number;) {
  }

  incrementAge() {
  }

  greeting(this: Person) {
    console.log(`Hello! My name is ${this.name}. I am ${this.age} years old.`);
  }
}

class Teacher extends Person {
  constructor(name: string, age: number, public subject: string) {
    super(name, age);
  }

  greeting() {
    console.log(`Hello! My name is ${this.name}. I am ${this.age} years old. I teach ${this.subject}`);
  }
}
```

面倒だと思いますが、上書きしましょう。

#protected修飾子
privateより少し緩い修飾子です。
class外では相変わらず使えませんが、継承先では使えます。

```class.ts
class Person {
  constructor(public readonly name: string, protected readonly age: number;) {
  }
```

#ゲッターとセッター
ES5以上のVerでのみ使えます。

**ゲッター**　何かを取得したときに、何かの関数を実行したいといったときに使うものです。

↓get　関数名で関数のように使えます。

```class.ts
class Teacher extends Person {
  get subject() {
    if(!this._subject) {
      throw new Error('There is no subject.');
    }
    return this._subject;
  }
}

const teacher = new Teacher('Quill', 38, 'Math');
console.log(teacher.subject);
```
teacher.subject
↑また、プロパティのように使えます。
　何か（teacher.subject）を取得したときに、何かを実行したい。そいうときに使います。


**セッター**　何かの値を代入/変更するときに何かの処理をしたい、といったときに使うものです。

１つのパラメーターを持つ必要があります。
ゲッターと同じ名前でも問題ありません。

↓teacher.subject = 'Music';のときにゲッターが実行されます。
↓そして今回だったら'Music'がパラメーターのvalueに当たります。

```class.ts
class Teacher extends Person {
  get subject() {
    if(!this._subject) {
      throw new Error('There is no subject.');
    }
    return this._subject;
  }

  set subject(value) {
    if(!this._subject) {
      throw new Error('There is no subject.');
    }    
    this._subject = value;
  }

const teacher = new Teacher('Quill', 38, 'Math');
teacher.subject = 'Music';
console.log(teacher.subject);
```

セッターは、ゲッターと名前が同じだと、今回でいうvalueの型も同じになります。
同じ型でないとエラーが出ます。

ゲッターと違う名前だと、valueはany型になります。

#static
newでのインスタンス化などを行わなくても、
staticで定義しておけばいつでもプロパティやメソッドやらが使えるというものです。

```class.ts
class Person {
  static species = 'Homo Sapiens';
  static isAdult(age: number) {
    if (age > 17) return true;
    return false;
  }
```

#Abstract
Abstract　＝　抽象的

あるプロパティ値の定義を必ず行ってほしいことを継承先のクラスへ伝えることができます。

abstract classは、インスタンスを生成できません。
なので、継承のためだけのclassということになります。


#constructorにprivateをつける
newでインスタンスを作ることができなくなります。
これは、シングルトーンパターンを実装するために使われます。

シングルトーンパターンとは
「classからインスタンスを１つしか作れない」というデザインパターンです。

```class.ts
  private constructor(name: string, age: number, private _subject: string) {
    super(name, age);
  }

  static getInstance() {
    if (Teacher.instance) return Teacher.instance;
    Teacher.instance = new Teacher('Quill', 38, 'Math');
    return Teacher.instance;
  }
```