[JavaScript] 2. クラスの継承

---

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)

---

#prototype の継承
JavaScriptでクラス継承を行うには、親クラスの prototype を継承します。

```text:書式
子のprototype = Object.create(<親のprototype>, {value: {constructor: <子のコンストラクタの指定>}});
```

[Object.create()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/create) は、指定した prototype オブジェクトを引き継いだ新たなオブジェクトを生成する関数です。
2つ目の引数は生成した prototype オブジェクトに持たせるプロパティを指定するハッシュオブジェクトです。ここで設定できるプロパティは決められおり、詳細は[こちら](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties)で確認してください。
クラスの継承では最低限、子クラスのコンストラクタ関数オブジェクトを指定します。

このように、子クラスの prototype を、親クラスの prototype を引き継いだオブジェクトで上書きすることで、親クラスを継承したクラスとすることができます。


#クラス継承の例
まず子クラスのコンストラクタを定義します。

```js:子クラスのコンストラクタ
    MySubClass = function(prop1, prop2, prop3) {
        MyClass.call(this, prop1, prop2);
        this.prop3 = prop3;
    }
```

コンストラクタの書き方は、基本的に普通のクラスと同じです。
コンストラクタ内で親クラスのコンストラクタを呼び出す場合は…

```text:書式
親クラス名.call(this, 引数, ...)
```

このようにします。

この段階ではまだ継承は行われていません。
この段階の MySubClass.prototype を console.log() で出力してみると、constructor プロパティが1つ定義されているだけなのがわかります。

次に継承を行います。

```js:継承
    MySubClass.prototype = Object.create(MyClass.prototype, {value: {constructor: MySubClass}});
```

前出の Object.create() を使って MyClass（親クラス）の prototype を継承した新たな prototype オブジェクトを生成し、先ほど定義した MySubClass（子クラス）の prototype を上書きします。

これで継承の定義は完了です。

#メソッドのオーバーライド
親クラスメソッドをオーバーライドすることも可能です。

```js:オーバーライド
    var p = MySubClass.prototype;
    p.methodA = function(arg1, arg2, arg3) {
        var parentResult = MyClass.prototype.methodA.call(this, arg1, arg2);
        return parentResult + this.prop3 + arg3;
    }
```

オーバーライドしたメソッドの中から、元のメソッドを呼び出したいときは…

```text:書式
親クラス名.prototype.メソッド名.call(this, 引数, ...)
```

このようにします。

#注意点
静的なプロパティ、メソッドは継承されません。

#サンプルコード
```js:js-class-extends.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;
    }
}

/**
 * サブクラス
 */
MySubClass: {
    /**
     * コンストラクタ
     */
    MySubClass = function(prop1, prop2, prop3) {
        // 親クラスのコンストラクタを呼ぶ
        MyClass.call(this, prop1, prop2);
        
        this.prop3 = prop3;
    }
    // MyClass を継承
    MySubClass.prototype = Object.create(MyClass.prototype, {value: {constructor: MySubClass}});
    // prototype をローカル変数へ
    var p = MySubClass.prototype;
    // methodA をオーバーライド
    p.methodA = function(arg1, arg2, arg3) {
        // 元の methodA を呼ぶ
        var parentResult = MyClass.prototype.methodA.call(this, arg1, arg2);
        return parentResult + this.prop3 + arg3;
    }
}

// MySubClassオブジェクトを生成
var obj = new MySubClass('aaa', 'bbb', 'ccc');
// MySubClass.methodA() を呼び出す
var result1 = obj.methodA('ddd', 'eee', 'fff');
```