[JavaScript] 1. クラスの定義

---

1. [クラスの定義](http://qiita.com/Koizumi-Greenwich/items/7a579c43084286dd38be)
2. [クラスの継承](http://qiita.com/Koizumi-Greenwich/items/96215899b8b61cc85e65)
3. [即時関数 と jQuery.readyイベント関数](http://qiita.com/Koizumi-Greenwich/items/d192ad98ca8b2449e4fd)
4. [即時関数でクラス定義](http://qiita.com/Koizumi-Greenwich/items/6f74230f35f2c5b9a46b)
5. [private プロパティ](http://qiita.com/Koizumi-Greenwich/items/f9e8a6dad4f049c89944)
6. [Object.defineProperty/ies でプロパティ/メソッド定義](http://qiita.com/Koizumi-Greenwich/items/1b827b4304538f2f8e37)

---

#JavaScriptにはクラスが無い...
最新の ECMA Script 6 にはクラス定義が実装されましたが、まだ対応していないブラウザがほとんどです（2015年11月現在）。
そこで、関数オブジェクトをクラスに見立てて擬似的にクラスのようなものを実現します。
擬似的なクラスの書き方には様々な方法がありますが、ここで解説する手法は Google が推奨するもので、コンストラクタを持ち、インスタンス化することで動的なオブジェクトとして扱えます。
また静的なメンバーを持つことも可能です。

***関数オブジェクト***
*JavaScriptでは関数もオブジェクトとして扱われます。*

#コンストラクタとプロパティ
関数オブジェクトそのものが、コンストラクタとなります。

```text:書式
クラス名 = function(仮引数, ...) {
    this.プロパティ名;            // プロパティの宣言のみ
    this.プロパティ名 = 仮引数;    // プロパティを宣言し、に引数値を代入
}
```

以下はコンストラクタの定義例です。

```js:MyClass.js
MyClass = function(prop1, prop2) {
    this.prop1 = prop1;
    this.prop2 = prop2;
}
```

#メソッド
関数オブジェクトには親オブジェクトへの参照である prototype プロパティを持っています。このプロパティに関数オブジェクトを追加することでメソッドのように扱えるようになります。

```text:書式1
クラス名.prototype.メソッド名 = function( ... ) {
    〜 メソッド内の処理 〜
}
```

多くのメソッドを定義するとコードが冗長になってしまうので、あらかじめローカル変数に prototype プロパティを代入しておくと便利です。

```text:書式2
var p = クラス名.prototype;    // prototypeをローカル変数に代入しておく
p.メソッド名 = function( ... ) {
    〜 メソッド内の処理 〜
}
```

以下、メソッド定義の例です。

```js:MyClass.js
var p = MyObject.prototype;
p.methodA = function(arg1, arg2) {
    return this.prop1 + this.prop2 + arg1 + arg2;
}
```

***prototype***
*prototype は JavaScript における親クラス、Javaで言うところの Objectクラス のようなものです。*


#インスタンスの生成
作成したクラスのインスタンスを生成します。

```text:書式
var 変数 = new MyClass(引数, ...);
```

##プロパティ、メソッドへのアクセス
以下のようにしてプロパティ、メソッドにアクセスします。

```text:書式
変数.プロパティ名
変数.メソッド名(引数, ...)
```

#ラベルブロック
この手法では、クラス全体を囲む仕組みがありません。そのためどこからどこまでがクラス定義なのかがわかりづらくなってしまいます。
そこで、 **ラベルブロック**を使ってクラス全体を囲むことで、コードを見やすくするとよいでしょう。

```text:書式
ラベル名: {
    〜 クラス定義 〜
}
```

#静的なプロパティ、メソッド
静的なプロパティやメソッドを持たせることも可能です。

```text:書式
クラス名.静的プロパティ名 = 値;

クラス名.静的メソッド名 = function(仮引数, ...) {
    〜 メソッドの処理 〜
}
```

これらへのアクセス方法は次の通りです。

```text:書式
クラス名.プロパティ名   ← プロパティにアクセス
クラス名.メソッド名( ... )  ← メソッドを呼び出す
```

動的メンバーと静的メンバーの違いは…

- 動的メンバー
 - プロパティ ... コンストラクタ関数内で定義する
 - メソッド ... コンストラクタ関数オブジェクトの prototype プロパティに追加する
- 静的メンバー
 - コンストラクタ関数オブジェクトに直接追加する

となります。

```js:MyClass.js
MyClass.staticProp1 = null;

MyClass.staticMethod = function(arg3) {
    return this.staticProp1 + arg3;
}
```


#サンプル
関数オブジェクト方式で作ったクラスとその使用例です。

```js:MyClass.js
/**
 * クラス MyClass
 */
MyClass: {
    /**
     * コンストラクタ
     */
    MyClass = function(prop1, prop2) {
        // プロパティの定義
        this.prop1 = prop1;
        this.prop2 = prop2;
    }
    // prototype をローカル変数へ
    var p = MyClass.prototype;
 
    /**
     * メソッド methodA
     */
    p.methodA = function(arg1, arg2) {
        return this.prop1 + this.prop2 + arg1 + arg2;
    }
    
    // 静的なプロパティ
    MyClass.staticProp1 = null;
    
    /**
     * 静的なメソッド
     */
    MyClass.staticMethodA = function(arg3) {
        return this.staticProp1 + arg3;
    }
}

// MyClassオブジェクトを生成
var obj = new MyClass('aaa', 'bbb');
// MyClass.methodA() を呼び出す
var result1 = obj.methodA('ccc', 'ddd');
// MyClass.staticProp1に値をセット
MyClass.staticProp1 = "XXX";
// MyClass.staticMethod() を呼び出す
var result2 = MyClass.staticMethodA("YYY");
```

#注意点
##アクセス制限
private アクセス制限も可能ですが、少々難解なコードになります。（[5.private プロパティ](http://qiita.com/Koizumi-Greenwich/items/f9e8a6dad4f049c89944)を参照）
protected はできません。

##this に注意!!
JavaScriptにおける *this* は、「呼び出し元オブジェクト」、「アクセス元オブジェクト」を表します。 **「オブジェクト自身」ではない** ので注意しましょう。