JavaScriptでスタイリッシュにクラスを作る - ①クラスの継承

# 前書き

[前の記事](http://qiita.com/tawatawa/items/0347ab06842434247b29)で、
JavaScriptって意外と面白い使い方ができるんだなーと感心したわけですが、
それならクラスの機能とかってどうなんじゃろ？　と思いまして。

JavaScriptでのクラスは

- そもそもクラス言語じゃないから機能が足りない
- アクセス修飾子がない
- アクセス権を考えるとプロトタイプが併用できない(しづらい)
- クラスとしての機能を考えると、コードが書きづらくなる

などなど、それなりに問題というか、微妙に扱いづらいイメージですので
この辺を上手くやれるクラス構築機能ができないもんか？　というのが事の発端です。


私が主に携っているスマホ関連のwebについては
ブラウザの実装が曖昧なものが多く、また端末の新旧でもブラウザバージョンが異なるため
ES5での実装を前提としています。

※少なくとも**アロー関数が動かない**という端末には遭遇したので
　ES2015は今のところ排除しています。

で、試しに作ってみたところ、意外にも結構いい感じにできてきた
(むしろ「**JavaScriptはこの縛りを見抜いていた・・・！？**」レベルで、必要な機能が存在してました)
ので、考え方などをプラグインの説明がてら投稿してみようと思います。

そもそもES2015でクラスあるよ！　というご時世ですが、
よろしければお付き合いいただけると嬉しいです。

尚、アクセス修飾子についての実装が凄まじく複雑になってしまったので
今回は前段として継承機能だけに絞った内容になっています。

## プラグイン

今のところのソースは⇒[こちら](https://github.com/tawaship/LaClass)です。
名前は **LaClass** としました。
**楽**に**クラス**を作りたいから、という安直なあれです。

2016/10/7時点での機能としては、

- 継承
- アクセス修飾子
- static
- final
- メンバのオーバーロード
- 上記全てがスタイリッシュ (重要)

あたりができたかな？　といった段階です。(デバッグはちゃんとしてません。)
とりあえず動かす程度は大丈夫ではないかと思います。

## 諸注意

- ES2015及びそれ以降の機能は使用しません。(知らずに使ってたらごめんなさい)
- 文中に出てくる「スタイリッシュ」というのは、「自分個人の感覚で」以下のようなものを指します。
	- きれいに見える
	- シンプルに書ける
	- オブジェクト指向っぽい雰囲気
- 実際にコーディングする際のスタイリッシュさを追求します。
- ある理由から 非strict mode での実装とします。

# クラスとはなんぞ

ご存知の通り、JavaScriptには他言語で言うところの「クラス」は存在しません。

が、関数をコンストラクタ呼び出しして作られたオブジェクトは
あたかもクラスインスタンスかのように振る舞うことができます。

というわけで、今回話題にする「クラス」は、このコンストラクタ呼び出しも含め
「クラスのように扱う事ができる、JavaScriptにおける様々な機構」
のことを指すことにします。

オブジェクトのメンバはstaticに似ていますし、
prototypeのメンバは、インスタンスメンバに似ている。
そういう感じです。

# クラスを作る

## クラスの定義の仕方
まずはクラス定義ですが、大きく分けて2パターンあります。

```Javascript:Javascript
function Parent() { // 文
}

var parentA = new Parent();
console.log(parentA); // Parent {}

var Parent = function() { // 式
};

var parentB = new Parent();
console.log(parentB); // Parent {}
```

俗に言うところの「function文」か「function式」かというやつですね。
今回は、継承機能の付与の関係で
function式の方を採用します。

# クラスの継承

クラスができたら、次はさっそく継承です。

## まずはただ単に親子関係を作る

クラスを二つ用意します。

```Javascript:Javascript
var Parent = function () {};
Parent.prototype.hoge = 1;

var Child = function() {}
```

継承のやり方は色々な方法があると思いますが、
私が主に使っているのは

```Javascript:Javascript
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

console.log((new Child()).hoge); // 1
```

のタイプです。
まず1行目で、親となるクラスのプロトタイプからオブジェクトを作り、子クラスのプロトタイプとします。
そのあと2行目で、子クラスのプロトタイプに設定されているコンストラクタを、子クラス自身に設定しなおします。

2行目については、実はなくても動作はします。
ただ、多重継承(1クラスに対しての多重継承ではなく、継承されたクラスを更に別のクラスに継承する方)していく際に
システムの作りによっては問題が出る場合があるので、入れておくことにします。

## スタイリッシュに呼び出したい

とはいえクラスが継承されるたびに継承コードを書くのは・・・ということで、当然関数にまとめます。

あまり外部プラグインを使用しないので、もしかすると調査が足りていないかもしれませんが
よくある継承機能としては
`_extends(Child, Parent);` ※もしくは引数の親子部分が逆
のような感じで、まったく別の関数に処理を任せるものが多そうです。

しかし、すこーしスタイリッシュさに欠ける感じが否めません。
ここはクラス自身に継承機能を持たせたいところです。

クラス自身はただの関数オブジェクトなので、
function型のprototypeをいじることで簡単に機能追加ができますが、
組み込みクラスをいじるのにはさすがに抵抗があるので
「コンストラクタに継承機能を付与する関数」を作ります。

```Class.js
var Class = function(c) {
	c.extends = function(parent) {
		this.prototype = Object.create(parent.prototype);
		this.prototype.constructor = this;
		
		return this;
	};
	
	return c;
};
```

関数名は少し悩みましたが、
大文字開始の【Class】は予約語になっていないようなので
とりあえずこれを使用することにします。

引数にコンストラクタを渡すことで、
関数【extends】を付与したコンストラクタを返します。
また、関数【extends】も、コンストラクタ自身を返すようにすることで
メソッドチェーンができるようにしておきます。

使い方は以下のようになります。

```Javascript:Javascript
var Parent = Class(function() {});
Parent.prototype.hoge = 1;

var Child = Class(function() Parent{}).extends(Parent); // スタイリッシュに違いない

console.log(new Child()).hoge; // 1
```

よくあるクラス定義の

class Child extends Parent
に、だいぶ近づいたような感じがします！

### 動作チェック

継承したクラスで親クラスのメンバをオーバーライドして、
影響がどうなるかをチェックします。

```Javascript:Javascript
var Parent = Class(function() {});
Parent.prototype.getHoge = function() {
	return this.hoge;
}
Parent.prototype.hoge = 1;

var Child = Class(function() {}).extends(Parent);
Child.prototype.hoge = 2;

var Brother = Class(function() {}).extends(Parent);

var GrandChild = Class(function() {}).extends(Child);

console.log((new Parent()).getHoge()); // 1
console.log((new Child()).getHoge()); // 2
console.log((new Brother()).getHoge()); // 1
console.log((new GrandChild()).getHoge()); // 2
```

大丈夫なようですね。

# まとめ

今回は事前準備として、クラスの定義部分だけの説明でした。
クラス定義だけなので、そんなに目新しいコードでもないかと思います。

むしろ次回予定の「メンバへのアクセス権(public, protected, private)の付与」
が、今回の思いつきの原点であり、実装の難しい所であり、プラグインのキモとなります。

次回分投稿しました。
⇒[JavaScriptでスタイリッシュにクラスを作る - ①クラスの継承](http://qiita.com/tawatawa/items/b66b81c76ead14d4739d)
こっからが本番だ！