JavaScript 継承のようなもの

# 最初に
pythonやrubyといった他の言語は割とわかりやすいですが、JSはprototypeがベースだから結構　異なる気がする。
たぶん[JavaScriptにおける継承のパターン4種類の概要と対比](http://postd.cc/javascript-inheritance-patterns/)とか参考にされていると思いますが、スコープ(っぽいもの)がわかりづらくあまり好みの書き方ではありません。 自分の好みの書き方で継承っぽいものをしてみます。
※ECMAScript 5です。 6からはclass,extendsを使って下さい。(class実装するの遅くない？)
# 結論
とりあえず、最初に結論を…

```js
var F1 = function(){
  this.a = "a"
  F1.prototype.print = function(){
    console.log(this.a);
  }
}
var F2 = function(){
  this.b = "b";
  F2.prototype.printa = function(){
    console.log(this.a);
  }
  F2.prototype.printb = function(){
    console.log(this.b);
  }
}
F2.prototype = new F1();//スコープ(っぽい)物の外で行う。(重要)

//main
var f2 = new F2();
f2.printa() // => "a"
f2.printb() // => "b"
f2.print() // "a"
```
`F2.prototype = new F1` 関数と変数両方を自分のprototypeへ追加できます。


# 検証みたいなの
## 環境
chrome  49.0.2623.110 m
firefox 45.0.1 + firebug
##パターン1　初っ端に追加

```js
var F1 = function(){
  this.a = "a"
  F1.prototype.print = function(){
    console.log(this.a);
  }
}
var F2 = function(){
  F2.prototype = new F1();//スコープ(っぽい)物の中で行う。
  this.b = "b";
  console.log(this.a) // => undefined
  F2.prototype.printa = function(){
    console.log(this.a);
  }
  F2.prototype.printb = function(){
    console.log(this.b);
  }
}

//main
var f2 = new F2();
f2.printa() // Uncaught TypeError: f2.printa is not a function
f2.printb() // 同じく
f2.print() // 同じく
```
ダメ。

```
f2 {b: "b"}
    _proto_:Object
    constructor:F2()
    _proto_:Object

```
勿論、プロパティにF1のプロパティはない。

## パターン2　少し後に追加

```js
var F1 = function(){
  this.a = "a"
  F1.prototype.print = function(){
    console.log(this.a);
  }
}
var F2 = function(){
  this.b = "b";
  console.log(this.a) // => undefined
  F2.prototype = new F1();
  F2.prototype.printa = function(){
    console.log(this.a);
  }
  F2.prototype.printb = function(){
    console.log(this.b);
  }
}

//main
var f2 = new F2();
f2.printa() // Uncaught TypeError: f2.printa is not a function
f2.printb() // 同上
f2.print() // 同上
```
パターン1と同じく　ダメ。
f2のプロパティも同じ。

## パターン3　2つの関数の間
```js
var F1 = function(){
  this.a = "a"
  F1.prototype.print = function(){
    console.log(this.a);
  }
}
var F2 = function(){
  this.b = "b";
  console.log(this.a) // => undefined
  F2.prototype.printa = function(){
    console.log(this.a);
  }
  F2.prototype = new F1();
  F2.prototype.printb = function(){
    console.log(this.b);
  }
}

//main
var f2 = new F2();
f2.prototype // undefined
f2.printb() // Uncaught TypeError: f2.printb is not a function
f2.print() // 同上
```
f2プロパティへ`printa`は登録されてるみたい。
f2を覗いてみる

```
f2 {b: "b"}
    b:"b"
    __proto__:Object
    constructor:function()
    printa:function()
        arguments:null
        caller:null
        length:0
        name:""
    prototype:Object
    __proto__:function()
    <function scope>
    __proto__:Object
```
F1はない。

## パターン4　一番最後

```js
var F1 = function(){
  this.a = "a"
  F1.prototype.print = function(){
    console.log(this.a);
  }
}
var F2 = function(){
  this.b = "b";
  console.log(this.a) // => undefined
  F2.prototype.printa = function(){
    console.log(this.a);
  }
  F2.prototype.printb = function(){
    console.log(this.b);
  }
  F2.prototype = new F1();//最後
}

//main
var f2 = new F2();
f2.printa() // undefined
f2.printb() // b
f2.print() // Uncaught TypeError: f2.print is not a function
```
`printb`は動いた。 
prototypeにF1はないから `printa`のaはundefinedとなっている。
f2のプロパティを見る。

```
F2 {b: "b"}
b:"b"
__proto__:Object
constructor:function()
printa:function()
    arguments:null
    caller:null
    length:0
    name:""
    prototype:Object
    __proto__:function()
    <function scope>
printb:function()
    arguments:null
    caller:null
    length:0
    name:""
    prototype:Object
    __proto__:function()
<function scope>
__proto__:Object
```
やはりF1はない。

##パターン5　スコープ外へ
結論にあるコードのf2プロパティ

```
F2 {b: "b"}b: "b"
    __proto__: F1
    a:"a"
    printa:function()
        //中はパターン4と同じ
    printb:function()
        //中はパターン4と同じ
    __proto__:Object

```
ちゃんとF1が追加されている。

# 検証まとめ
パターン1~4はF2の関数を定義している間にそのprototypeに違う関数のprototypeを入れようとするが、そもそも入れるための器が無かった。
(newした時の`__proto__`はnewされる関数のprototypeを参照します。[ソースはMDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/proto))
F2自体を定義するために、スコープの外でprototypeに追加する必要がある。(当たり前と言えば当たり前)

#　最後に
ECMAScript 6を使うと幸せになる。(はず)
しかし、prototypeからは逃れられない。

書き方とかもっと良いものがあれば是非コメント下さい。