プロトタイプチェーン


このエントリは、プロトタイプチェーンについてまとめたメモです。
コード関連は、Node.js の REPL で確認してます。


# prototype プロパティ

全ての関数は prototype という名前のプロパティを持ちます。中身は Object です。

```javascript
function A() {}
console.log(A.prototype);		// {} と表示
```

Object なので変数や関数の追加ができます。

```javascript
function B() {}
B.prototype.a = 123;
B.prototype.b = 'bbb';
B.prototype.c = function() {
    console.log('B.prototype.c');
}
console.log(B.prototype);       // { a: 123, b: 'bbb', c: [Function] }
```

この prototype を使用すると継承を行うことができます。

```javascript
function C() {}
C.prototype.show = function() {
    console.log('C.prototype.show');
}
var c1 = new C();
c1.show();        // 'C.prototype.show' と表示
```

new でオブジェクトを生成した後に関数を追加したり変更しても反映されます。

```javascript
function D() {}
D.prototype.show = function() {
    console.log('D.prototype.show');
}
var d1 = new D();

// d1オブジェクトを生成後にshow2関数を追加する
D.prototype.show2 = function() {
    console.log('D.prototype.show2');
}
d1.show();        // 'D.prototype.show' と表示
d1.show2();       // 'D.prototype.show2' と表示

// show関数の内容を変更する
D.prototype.show = function() {
    console.log('D.prototype.show - changed!');
}
d1.show();        // 'D.prototype.show - changed!' と表示
```


# \_\_proto\_\_ プロパティ

\_\_proto\_\_ プロパティは全てのオブジェクトが持つプロパティで、オブジェクト生成に使ったコンストラクタの prototype プロパティへの参照です。


```javascript
// ビルトインオブジェクト
var o = {};
console.log(o.__proto__);                         // {}
console.log(o.__proto__ === Object.prototype);    // Objectのprototype
var a = [];
console.log(a.__proto__);                         // []
console.log(a.__proto__ === Array.prototype);     // Arrayのprototype
var s = "123";
console.log(s.__proto__);                         // ''
console.log(s.__proto__ === String.prototype);    // Stringのprototype
// 独自関数
function E() {}
E.prototype.show = function() {}
var e1 = new E();
console.log(e1.__proto__);                        // { show: [Function] }
console.log(e1.__proto__ === E.prototype);        // E関数のprototype
```


オブジェクトのプロパティを探す場合、次の順番で探します。
1. オブジェクト自身のプロパティ
2. \_\_proto\_\_ のプロパティ（継承元の prototype）
3. 2 の \_\_proto\_\_ のプロパティ（継承元の prototype の \_\_proto\_\_）
4. \_\_proto\_\_ が null になるまで 2, 3 を繰り返す（Object.prototype の \_\_proto\_\_ は null ）

このようにプロパティを探すために \_\_proto\_\_ を辿る連鎖をプロパティチェーンと呼びます。

もう少し詳しく見ていきます。
次の例は、G → H → Object と継承した場合です。


```javascript
var H = function() {};
H.prototype.show1 = function() {
	console.log('H.prototype.show');
}
// H を継承して G を作成
var G = function() {};
G.prototype = Object.create(H.prototype);    // 継承元の prototype を指定
G.prototype.constructor = G;                 // Object.createはconstructorを変更しないため
G.prototype.show2 = function() {
	console.log('G.prototype.show');
}
var hh = new H();
var gg = new G();

// 検証

// H オブジェクト
console.log(H.prototype.__proto__ === Object.prototype);              // true

// G オブジェクト
console.log(G.prototype.__proto__ === H.prototype);                   // true
console.log(G.prototype.__proto__.__proto__ === Object.prototype);    // true

// ggオブジェクト
console.log(gg.__proto__ === G.prototype);                            // true
console.log(gg.__proto__.__proto__ === H.prototype);                  // true
console.log(gg.__proto__.__proto__.__proto__ === Object.prototype);   // true
console.log(gg.__proto__.__proto__.__proto__.__proto__ === null);     // true


// 実行
hh.show1();        // 'H.prototype.show' と表示
gg.show1();        // 'H.prototype.show' と表示
gg.show2();        // 'G.prototype.show' と表示
hh.show2();        // TypeError: hh.show2 is not a function
```


この G と H のコードが実行された後のオブジェクトの様子をJSON形式のイメージで表します。


```json
gg : {
    __proto__ : G.prototype を参照
}
hh : {
    __proto__ : H.prototype を参照
}
G : {
    __proto__ : Function.prototype を参照
    prototype : {
        constructor : G,
        __proto__ : H.prototype を参照
    }
}
H : {
    __proto__ : Function.prototype を参照
    prototype : {
        constructor : H,
        __proto__ : Object.prototype を参照
    }
}
Object : {
    __proto__ : Function.prototype を参照
    prototype : {
        constructor : Object,
        __proto__ : null
    }
}
Function : {
    __proto__ : Function.prototype を参照
    prototype : {
        constructor : Function,
        __proto__ : Object.prototype を参照
    }
}
```


ggオブジェクトが show1 プロパティを探す場合は、
1. gg の show1 プロパティを探す。無いので 2へ
2. gg の \_\_proto\_\_ （G.prototype）で show1 プロパティを探す。無いので 3へ
3. gg の \_\_proto\_\_ の \_\_proto\_\_ （H.prototype）で show1 プロパティを探す。あったのでこれを使用する。

ということを行っています。

hh オブジェクトが show2 プロパティを探す場合は、
1. hh の show2 プロパティを探す。無いので 2へ
2. hh の \_\_proto\_\_ （H.prototype）で show2 プロパティを探す。無いので 3へ
3. hh の \_\_proto\_\_ の \_\_proto\_\_ （Object.prototype）で show2 プロパティを探す。無いので 4へ。
4. hh の \_\_proto\_\_ の \_\_proto\_\_ の \_\_proto\_\_ （Object.prototype.__proto__）は null なので探索終了。なかったのでエラー。

となります。



# 参考

http://maeharin.hatenablog.com/entry/20130215/javascript_prototype_chain
http://d.hatena.ne.jp/m-hiyama/20050908/1126154117
http://qiita.com/LightSpeedC/items/d307d809ecf2710bd957
http://d.hatena.ne.jp/m-hiyama/20051017/1129510043
https://gist.github.com/y-yu/3301790