JavaScriptのinheritanceについて part1

# 初めに
前回は [JavaScriptのPrototypeについて](https://qiita.com/hu-yu/items/d6d9f3ca0f1dd98f2bcc) でプロトタイプ、プロトタイプチェーンをまとめてみました。
今回はConstructor Functionの**Inheritance（継承）** 、四つの方法をまとめていきたいと思います。

# Inheritance
ここから継承の仕方を紹介したいと思います。
デモのためにまずは2つのコンストラクタ関数から行きます。
```jsx
function Animal() {
  this.species = 'animal'
}

function Cat(name, color) {
  this.name = name
  this.color = color
}
```
コンストラクタ関数`Animal`を、コンストラクタ関数`Cat`に継承させるのがデモの目的です。

## by binding methods (call, apply...)
```jsx
function Animal() {
  this.species = 'animal'
}

function Cat(name, color) {
  Animal.apply(this)
  this.name = name
  this.color = color
}

const cat1 = new Cat('Mio', 'white')
console.log(cat1.name, cat1.color) // Mio white
console.log(cat1.species) // animal
console.log(cat1) // Cat { species: 'animal', name: 'Mio', color: 'white' }
```
一番目はバインドメソッドで強制的に親の`this`コンテキストを子へ変更する、つまり`Animal`の`this`オブジェクトのプロパティを、`Cat`の`this`オブジェクトに入れるという継承方法です。
ここで`apply()`でバインドする前の状態を見てみたいと思います。
まずは`Cat.prototype`オブジェクトに`species`プロパティと`favorite`メソッドを書き込んでみて、
```jsx
function Cat(name, color) {
  // Animal.apply(this)
  this.name = name
  this.color = color
}

Cat.prototype.species = 'cat'
Cat.prototype.favorite = () => {
  console.log('eat and sleep')
}

const cat1 = new Cat('Mio', 'white')
console.log(cat1.name, cat1.color) // Mio white
console.log(cat1.species) // cat
cat1.favorite() // eat and sleep

console.log(cat1) // Cat { name: 'Mio', color: 'white' }
console.log(Cat.prototype) // { species: 'cat', favorite: [Function (anonymous)] }
```
そしたら`Animal.apply(this)`でバインドすると何か変わるでしょうか。
```jsx
console.log(cat1.name, cat1.color) // Mio white
console.log(cat1.species) // animal
cat1.favorite() // eat and sleep

console.log(cat1) // Cat { species: 'animal', name: 'Mio', color: 'white' }
console.log(Cat.prototype) // { species: 'cat', favorite: [Function (anonymous)] }
```
プロトタイプチェーンというのは自分のオブジェクトに持ってないものなら、自分のプロトタイプ、つまり上に探していきますね。

`Cat`は`Animal`からの`species`が強制的にバインドされ`Cat`の`this`オブジェクトの一部として書き込まれたで、`this`オブジェクトですでに`species`が見つかった場合、上にはいきません。それで自分のプロトタイプ`Cat.prototype.species = 'cat'`が使えなくなりました。

もちろん`Cat.prototype`のプロパティたちは書き換えられたわけではないので、プロパティが重複しない以上`Cat.prototype`にたどり着いてプロパティを利用することができます。（例えば`favorite`メソッド）

（実際四つの方法を分かったうえ、バインドメソッドがプロトタイプチェーンへの変動しないところが、一番混乱生じにくい方法だと思います。）

↓は検定メソッドの結果です。
```jsx
console.log(cat1.hasOwnProperty('species')) // true
console.log(Cat.prototype.isPrototypeOf(cat1)) // true
console.log(cat1.constructor === Cat) // true
console.log(cat1.constructor === Animal) // false
```
`console.log(cat1.hasOwnProperty('species')) // true`から、`species`がコンストラクタ関数（ローカル）から継承したことが分かりました。

## by another new instance
二番目は`prototype`プロパティの操作ですが、
```jsx
function Animal() {
  this.species = 'animal'
}

function Cat(name, color) {
  this.name = name
  this.color = color
}

const cat1 = new Cat('Mio', 'white')
console.log(Cat.prototype) // {}
console.log(cat1.constructor) // [Function: Cat]

Cat.prototype = new Animal()
console.log(Cat.prototype) // Animal { species: 'animal' }
console.log(cat1.constructor) // [Function: Cat]
```
一番目のように`Cat.prototype`のプロパティ、つまり`prototype`オブジェクトのプロパティへの書き込みではなく、継承したい親関数のインスタンスで**上書きする**んです。このやり方は、元に持っている`prototype`オブジェクトを削除するように見えますが、実際はちょっと違います。

まずは`Cat`のプロトタイプが`Animal`のインスタンスで上書きされた後に、`Cat`の新しいインスタンス`cat2`を作りましょう。
```jsx
const cat2 = new Cat('Tora', 'orange')
console.log(cat2.__proto__) // Animal { species: 'animal' }
console.log(cat2.__proto__ === Cat.prototype) // true
console.log(cat2.constructor) // [Function: Animal]
```
インスタンスには`constructor`がないため、自分のコンストラクタ関数のプロトタイプへたどり着き、`cat2.constructor`が`Animal`に指しています。

なのでこの`Cat.prototype = new Animal()`という、継承対象のインスタンスで自分の`prototype`への上書きが、継承前から創り出した自分のインスタンスの継承関係に混乱が生じてしまいます。

`cat1`も`cat2`も`Cat`のインスタンスだけど、`cat1`は**pass by sharing**の影響で前の歴史（値）に取り残されたままです。
```jsx
console.log(cat1 instanceof Cat) // false
console.log(cat2 instanceof Cat) // true

console.log(Cat.prototype.isPrototypeOf(cat1)) // false
console.log(Cat.prototype.isPrototypeOf(cat2)) // true
```
ちょっと別の話になりますが、まずは**pass by sharing**ってどういうことから説明したいと思います。
一般の認識ではJavaScriptは**pass by value**と**pass by reference**二つがあります。実際JavaScriptの**pass by reference**ではなく**pass by sharing**っていうほうが適切です。（実際JavaScriptは**pass by value**しかないんですが、区別のために**pass by sharing**という技術上の言い方が出てきました。）

[Is JavaScript a pass-by-reference or pass-by-value language? - Stackoverflow](https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language)

**pass by reference**は値が連動することに対して、**pass by sharing**は値の記憶方法として、一つの変数に一つの値のように、一つの参照をコピーして記憶することで**連動はできません**。

**7/16補足：この文章の後、[JavaScriptのObjectのDeep copyメソッドについて](https://qiita.com/hu-yu/items/0ccd1b57067feeb35a2d#shallow-copy-vs-deep-copy)でpass by valueの説明図を作成しました。**

`cat1`が作り出された当初、親の`Cat`、`Cat.prototype`は`{}`で`constructor`も自分自身に指しているので、`cat1`はそれを参照しています。

`Cat.prototype = new Animal()`で新しい値（`Animal`）が付与され、そこから生まれた`cat2`が新しい値を参照するので、`Cat`のインスタンスとして`instanceof`も`constructor`も新しい値に従ってうまくいきましたが、`cat1`古い値を参照したせいで、`Cat`のインスタンスすら認めてもらえなくなりました。

きっと、どこかでこれ↓で解決できるんじゃない？って
```jsx
Cat.prototype.constructor = Cat

console.log(cat1.constructor) // [Function: Cat]
console.log(cat2.constructor) // [Function: Cat]

console.log(cat1 instanceof Cat) // false
console.log(cat2 instanceof Cat) // true

console.log(Cat.prototype.isPrototypeOf(cat1)) // false
console.log(Cat.prototype.isPrototypeOf(cat2)) // true

console.log(cat1.species) // undefined
console.log(cat2.species) // animal

console.log(cat2) // Cat { name: 'Tora', color: 'orange' }
```
確かに、`constructor`は可変だから新しい参照を記憶している`cat2`が自分にない`constructor`プロパティが`Cat.prototype.constructor`の変化によって変わったように見えましたが。（遠回りのような言い方してすみません、要するに`cat2`の`constructor`がないから親の`constructor`にたどり着いてその新しい値をログしただけです。**pass by reference**で連動したわけではありません。）

`cat1`には`instanceof`はだめでした。`isPrototypeOf()`もだめでした。古い値を参照している`cat1`には救いはありません...。

この方法で`prototype`オブジェクトを削除ではなく、新しい値を付与することで新しい参照が記憶されますが、古い値は消えたのではなくちゃんと生きていて、利用されている限りどこかで保存されています。

`cat2`のように創られた時点ですでに新しい参照に従うので問題はありません。
これはけっして悪い方法ではありませんが、
ただ **古いインスタンスには、救いようのない継承方法** なので、プロトタイプチェーンが長ければ要注意です。

## by prototype property
三番目は、二番目の改善版です。ここは継承対象のインスタンスではなく、`prototype`を継承するのです。これで継承するたびに`new`でインスタンスを創ることなく、メモリーに優しいのです。
```jsx
function Animal() { }
Animal.prototype.species = 'animal'

function Cat(name, color) {
  this.name = name
  this.color = color
}

const cat1 = new Cat('Mio', 'white')
console.log(Cat.prototype) // {}
console.log(cat1.constructor) // [Function: Cat]
console.log(cat1 instanceof Cat) // true
console.log(Cat.prototype.isPrototypeOf(cat1)) // true

Cat.prototype = Animal.prototype
console.log(cat1 instanceof Cat) // false
console.log(Cat.prototype.isPrototypeOf(cat1)) // false

Cat.prototype.constructor = Cat
console.log(cat1 instanceof Cat) // false
console.log(Cat.prototype.isPrototypeOf(cat1)) // false
```
でもやはり、古いインスタンスには救いがないです。
```jsx
const cat2 = new Cat('Tora', 'orange')
console.log(cat2 instanceof Cat) // true
console.log(Cat.prototype.isPrototypeOf(cat2)) // true
console.log(cat2) // Cat { name: 'Tora', color: 'orange' }
console.log(cat2.species) // animal

console.log(Cat.prototype.constructor) // [Function: Cat]
console.log(Animal.prototype.constructor) // [Function: Cat]

console.log(Cat.prototype) // { species: 'animal' }
console.log(Animal.prototype) // { species: 'animal' }
```
でもこのやり方では、`Cat.prototype`と`Animal.prototype`は同じオブジェクトをシェアしているので、片方を変更したらもう片方も変更されてしまいます。
```jsx
Cat.prototype.favorite1 = () => {
  console.log('fruit is yummy!')
}

cat2.favorite1() // fruit is yummy!
console.log(Cat.prototype)
// { species: 'animal', favorite1: [Function (anonymous)] }
console.log(Animal.prototype)
// { species: 'animal', favorite1: [Function (anonymous)] }
```
```jsx
Animal.prototype.favorite2 = () => {
  console.log('sleep and play')
}

cat2.favorite2() // sleep and play
console.log(Cat.prototype)
// {
//   species: 'animal',
//   favorite1: [Function (anonymous)],
//   favorite2: [Function (anonymous)]
// }
console.log(Animal.prototype)
// {
//   species: 'animal',
//   favorite1: [Function (anonymous)],
//   favorite2: [Function (anonymous)]
// }
```
## by function() {}
そして四番目は三番目の改善版です。
片方の`prototype`を変更しても、もう片方が影響されないように、両方の間に空の関数（オブジェクト）を利用して継承対象の`prototype`プロパティを保存する。
```jsx
function Animal() { }
Animal.prototype.species = 'animal'

function Cat(name, color) {
  this.name = name
  this.color = color
}

console.log(Cat) // [Function: Cat]
console.log(Cat.prototype) // {}
```
```jsx
const F = function () { }
F.prototype = Animal.prototype

Cat.prototype = new F()

console.log(Cat) // [Function: Cat]
console.log(Cat.prototype) // Animal {}
```
```jsx
Cat.prototype.constructor = Cat

console.log(Cat) // [Function: Cat]
console.log(Cat.prototype) // Animal { constructor: [Function: Cat] }

// console.log(Animal) // [Function: Animal]
// console.log(Animal.prototype) // { species: 'animal' }
```
ここまで来たら`Cat.prototype`の動きも分かりやすくなると思います。
`Cat.prototype`：
`{}`（関数の`prototype`）
↓
`Animal {}`（Fのインスタンスによって`Animal.prototype`を継承）
↓
`Animal { constructor: [Function: Cat] }`
（Cat.prototype.constructorで`constructor`プロパティに新しい値を付与）

そして空関数`F`のインスタンスのおかげで、
```jsx
const cat2 = new Cat('Tora', 'orange')

Cat.prototype.favorite1 = () => {
  console.log('fruit is yummy!')
}


cat2.favorite1() // fruit is yummy!
console.log(Cat.prototype)
// Animal {
// constructor: [Function: Cat],
//   favorite1: [Function(anonymous)]
// }
console.log(Animal.prototype) // { species: 'animal' }
```
```jsx
Animal.prototype.favorite2 = () => {
  console.log('sleep and play')
}

cat2.favorite2() // sleep and play
console.log(Cat.prototype)
// Animal {
//   constructor: [Function: Cat],
//   favorite1: [Function (anonymous)]
// }
console.log(Animal.prototype)
// { species: 'animal', favorite2: [Function (anonymous)] }
```
お互い影響されずに無事に継承しました。

# 感想
今回は前回の続き、コンストラクタ関数の継承をまとめてみました。決してどれの方法がいいか悪いか、を強調するのではなく、なぜこうなる？次の方法でどう改善されていくか、そしてどのような課題が残されていたかを語りたかったです。自分にふさわしいプロトタイプチェーンの書き方についてまだまだ探索中です。引き続き頑張ります。次回はコンストラクタ関数を使わず継承する方法についてまとめていきたいと思います。