ES5とTypeScriptでクラスの実装を比べてみる


これまでのJavaScriptではclass文がなく、代わりに関数を使用してclassを実装していきます。このあたりが、class文に慣れた方がJavaScriptに戸惑う原因にもなっていると思います。

##classを実装してみる

ここでは以下の流れのPersonクラスを作ります。

1.  Personクラスを定義
2.  nameプロパティをセット
3.  say、walkメソッドを実装
4.  インスタンスを生成
5.  メソッドを実行


### JavaScriptで実装してみる
今まで通りJavaScriptでPersonというクラスを実装してみたいと思います。

```js

var Person = function(name){
	this.name = name || "dammy";
}

Person.prototype.say = function() {
	console.log("Hello, I'm " + this.name);
};

Person.prototype.walk = function() {
	console.log(this.name + " is walking");
};

var p = new Person("Yuta");

// Hello, I'm Yuta
p.say();

// Yuta is walking
p.walk();

```

### TypeScriptで実装してみる

今度はTypeScriptでclassを実装してみたいと思います。

```ts

class Person {
    constructor(
        private name:string = "dammy"
    ) {}
    
    public say():void {
    	console.log("Hello, I'm " + this.name);
    }
    
    public walk():void {
    	console.log(this.name + " is walking");
    }
}

var p = new Person("Yuta");

// Hello, I'm Yuta
p.say();

// Yuta is walking
p.walk();

```

1行目：classを定義しています。
2行目：クラスからインスタンスを作成した際に、自動的に実行されるメソッドで、主に初期化などを行います。引数に初期値を設定することができます。
privateやpublicはアクセス修飾子と呼ばれています。privateはクラス内のアクセスのみ許可しています。publicはクラス外のアクセスを許可します。
一般的にはプロパティはprivate、メソッドをpublicにするケースが多いと思います。


##classを継承してみる
今度はPersonクラスを継承してPhotographerクラスを実装したいと思います。

1.  Photographerクラスを定義
2.  PhotographerクラスがPersonクラスを継承
3.  name,cameraプロパティをセット
4.  sayメソッドをオーバーライド
5.  release,hasCameraメソッドを定義
6.  インスタンスを生成
7.  メソッドを実行


### JavaScriptで実装してみる
上と同じく従来通りのJavaScriptで記述します。

#### Personクラス

```js

var Person = function(name){
    this.name = name || "dammy";
}

Person.prototype.say = function() {
  console.log("Hello, I'm " + this.name);
};

Person.prototype.walk = function() {
  console.log(this.name + " is walking");
};

```
#### Photographerクラス

```js

var Photographer = function(name,camera){
    this.name = name || "dammy";
    this.camera = camera || "";
}

// Personを継承
Photographer.prototype = Object.create(Person.prototype);

Photographer.prototype.say = function() {
  console.log("Hello, I'm " + this.name + "! My job is photographer");
};

Photographer.prototype.release = function() {
  console.log("take a picture");
};

Photographer.prototype.hasCamera = function() {
  console.log(this.camera? true : false);
};

var photographer = new Photographer("Yuta","Nikon S2");

// Hello, I'm Yuta! My job is photographer
photographer.say();

// take a picture
photographer.release();

// true
photographer.hasCamera();

// Yuta is walking
photographer.walk();

```

### TypeScriptで実装してみる
#### Personクラス
```ts

class Person {
    constructor(
    	//private -> protected
    	protected name:string = "dammy"
    ) {}

    public say():void {
        console.log("Hello, I'm " + this.name);
    }

    public walk():void {
        console.log(this.name + " is walking");
    }
}
```

Personクラスを少し書き直しました。
constructorでのnameをprivateからprotectedに変更しています。
protectedにする事で継承先からアクセスする事ができます。

#### Photographerクラス
```ts

class Photographer extends Person {
    constructor(
        protected name:string = 'dammy',
        private camera:string = ''
    ){
        super();
    }

    public say():void {
        console.log("Hello, I'm " + this.name + "! My job is photographer");
    }

    public release():void {
        console.log("take a picture");
    }

    public hasCamera():void {
        console.log(this.camera? true : false);
    }
}

var photographer = new Photographer("Yuta","Nikon S2");

// Hello, I'm Yuta! My job is photographer
photographer.say();

// take a picture
photographer.release();

// true
photographer.hasCamera();

// Yuta is walking
photographer.walk();
```

継承の見通しが良くなりました。クラスは宣言時にPersonを継承していることがわかります。
constructor内でsuper()を呼ぶことで、PhotographerクラスもPersonクラスで定義されているメソッドを呼ぶことがで、行の最後でphotographer.work()を確認することができます。

## まとめ
今回はクラスについてまとめました。TypeScriptも選択肢のひとつに上がるようになるといいなと思ってます！