JavaScriptのinheritanceについて  part2

# 初めに
前回でコンストラクタ関数の継承方法をまとめて紹介しました。
[JavaScriptのinheritanceについて（Constructor Function）](https://qiita.com/hu-yu/items/13635160a4616d6d1c0d)
今回はコンストラクタ関数を使わない方法をまとめたいと思います。

↓は今回デモの初期コードです。
```jsx
const Person = {
  nation: 'Japan'
}

const Occupation = {
  career: 'Business Man'
}
```

# `object()`
これは`json`の発明者Douglas Crockfordの発想です。
```jsx
function object(obj) {
  function F() { }
  F.prototype = obj
  return new F()
}
```
コンストラクタ関数でなく、一般関数の内部に空関数のプロトタイプに継承対象のプロパティやメソッドを受け継がせ、新しいイスタンスを返すという方法です。
```jsx
const Taro = object(Person)
console.log(Taro) // {}

Taro.career = Occupation.career

console.log(Taro.nation) // Japan
console.log(Taro.career) // Business Man

console.log(Taro.hasOwnProperty('nation')) // false // inherited from Person
console.log(Taro.hasOwnProperty('career')) // true
console.log(Taro.__proto__) // { nation: 'Japan' }
```
変数`Taro`は関数`F`の新しいインスタンスが付与され、同じ親`F`のプロトタイプから受け継いだオブジェクト`{ nation: 'Japan' }`が利用できるようになります。
`F`は空関数だから、`Taro`はローカルから`'nation'`プロパティを受け継いだのではなかったため、`hasOwnProperty()`の判定では`false`になります。

簡単に言うと、`object()`はインスタンスの親の`prototype`プロパティを継承対象へ変えることで継承を実現させました。

**関数`F`は`new`でインスタンスを創るからコンストラクタ関数じゃないんですか？**

確かに私も書きながら疑問に思います。[前回の文章](https://qiita.com/hu-yu/items/13635160a4616d6d1c0d#by-function-)書くとき、コンストラクタ関数の定義が`new`でインスタンス創るとき`this`がコンテキストを自分のスコープを指すということで、`this`オブジェクトで自分のスコープにプロパティを保存するという仕組みを書きましたが、でもこれはコンストラクタ関数の特徴でした。

もう一度調べたら、実はコンストラクタ関数というのはただの関数です。
関数を創るにつれて`constructor`プロパティも創られ、`new`を通じてインスタンスを創ると、自分の親である関数に参照（値）を保存し、その親がコンストラクタ関数です。

**なのでこの`object()`は間違いなくコンストラクタ関数を用いた継承方法です。**

# Copy
ここからCopy方法を紹介したいと思います。
## Shallow copy
```jsx
function extendCopy(obj) {
  let copy = {}

  for (let item in obj) {
    copy[item] = obj[item]
  }

  copy.uber = obj
  return copy
}

const Taro = extendCopy(Person)
console.log(Taro)
// { nation: 'Japan', uber: { nation: 'Japan' } }

Taro.career = Occupation.career

console.log(Taro.nation) // Japan
console.log(Taro.career) // Business Man
console.log(Taro.uber) // { nation: 'Japan' }
```
**Shallow copy**は浅いコピーのことです。
関数`extendCopy`のように空オブジェクト`copy`に、`obj`にある全ての`item`を参照し入れさせるということで、参照元は`obj`オブジェクトにあります。
そして`copy.uber`で自分の参照元が`obj`とのことを明記します。（uberのドイツ語が**その上**という意味です。）

変数`Taro`はコピーされたオブジェクトを受け取り、オブジェクトのプロパティやメソッドを使うようになります。

もしここで参照元に新しいプロパティができたらどうなるでしょう。
```jsx
Person.birthPlaces = ['Tokyo', 'Osaka', 'Hokaidou']

const Jiro = extendCopy(Person)
Jiro.career = Occupation.career

console.log(Jiro.nation) // Japan
console.log(Jiro.career) // Business Man
console.log(Jiro.birthPlaces)
// [ 'Tokyo', 'Osaka', 'Hokaidou' ]
console.log(Jiro.uber)
// { nation: 'Japan', birthPlaces: [ 'Tokyo', 'Osaka', 'Hokaidou' ] }

console.log(Taro.birthPlaces) // undefined
```
変数`Jiro`のように、新しいプロパティが書き込まれた後にコピーされたオブジェクトを保存したから、新しいプロパティが使えますが、`Taro`は保存したオブジェクトには`birthPlaces`がないため使えないです。

そしてこの**Shallow copy**方法に一番デメリットなところです。
もし`Jiro`のプロパティを操作したらどうなるでしょう。
```jsx
Jiro.birthPlaces.push('Fukuoka')
console.log(Jiro.birthPlaces)
// [ 'Tokyo', 'Osaka', 'Hokaidou', 'Fukuoka' ]
console.log(Person.birthPlaces)
// [ 'Tokyo', 'Osaka', 'Hokaidou', 'Fukuoka' ]

// note: JQuery
```
`Jiro`も`Person`も同じオブジェクト（参照元）を保存しているので、片方がプロパティを変更したらもう片方を影響してしまいます。

## Deep copy
**Deep copy**
```jsx
function deepCopy(obj, copy) {
  let copies = copy || {}

  for (let item in obj) {
    if (typeof obj[item] === 'object') {
      copies[item] = (obj[item].constructor === Array) ? [] : {}

      deepCopy(obj[item], copies[item])
    } else {
      copies[item] = obj[item]
    }
  }
  return copies
}

Person.birthPlaces = ['Tokyo', 'Osaka', 'Hokaidou']

const Taro = deepCopy(Person)
Taro.career = Occupation.career

console.log(Taro.nation) // Japan
console.log(Taro.career) // Business Man
console.log(Taro.birthPlaces)
// [ 'Tokyo', 'Osaka', 'Hokaidou' ]
```
**Deep copy**は深いコピー、つまり参照元を保存するのでなく、その中のプロパティをコピーして、プロパティを保存する新しい参照元を創り出すということです。

最初この方法を見たとき分かりづらいだなあって思っちゃいました。
自分で変数のネーミングを変えたら少し良くなってきて、この部分も少し理解できました。
```jsx
  for (let item in obj) {
    if (typeof obj[item] === 'object') {
      copies[item] = (obj[item].constructor === Array) ? [] : {}

      deepCopy(obj[item], copies[item])
    } else {
      copies[item] = obj[item]
    }
  }
  return copies
```
つまり`obj`プロパティの中には`Array`配列に該当するものがあれば、空の配列を返してもらう。そして該当の配列と空の配列と共にもう一回関数`deepCopy`に入れて、該当配列の値をコピーしてから`retrun`。`obj`の`for`ループが終わるまでこの作業を続けるんです。

このやり方では完全に`obj`のプロパティをコピーして新しいオブジェクト、新しい参照を返すから、これで`Taro`オブジェクトにどんな操作しても`Person`オブジェクトに影響を与えることができません。
```jsx
Taro.birthPlaces.push('Fukuoka')

console.log(Taro.birthPlaces)
// [ 'Tokyo', 'Osaka', 'Hokaidou', 'Fukuoka' ]
console.log(Person.birthPlaces)
// [ 'Tokyo', 'Osaka', 'Hokaidou' ]
```
逆に`Person`も、`Taro`に影響できません。

↓は別の検証です。もし配列とオブジェクトを`push()`したらどうなる話です。
```jsx
Person.birthPlaces.push(['A', 'B', 'C'])
console.log(Person.birthPlaces)
// [ 'Tokyo', 'Osaka', 'Hokaidou', [ 'A', 'B', 'C' ] ]

Person.birthPlaces.push({
  E: 1,
  F: 2,
  G: 3,
})
console.log(Person.birthPlaces)
// [
//   'Tokyo',
//   'Osaka',
//   'Hokaidou',
//   ['A', 'B', 'C'],
//   { E: 1, F: 2, G: 3 }
// ]
console.log(Person)
// {
//   nation: 'Japan',
//     birthPlaces: [
//       'Tokyo',
//       'Osaka',
//       'Hokaidou',
//       ['A', 'B', 'C'],
//       { E: 1, F: 2, G: 3 }
//     ]
// }
console.log(Taro.birthPlaces)
// [ 'Tokyo', 'Osaka', 'Hokaidou', 'Fukuoka' ]
console.log(Person.birthPlaces[4].E) // 1

// note: JQuery
```
データ（プロパティ）の取り出し方がさらに複雑になる気がする...。

# まとめ
`object()`は[JavaScriptのinheritanceについて（Constructor Function）](https://qiita.com/hu-yu/items/13635160a4616d6d1c0d#by-function-)で空関数という媒介で継承を実現させたが、**shallow copy**も**deep copy**本当の意味では継承ではなくデータをコピーして保存するだけです。copyのどちらでもJQueryで使われる継承方法で、どういった継承を行ったかこれでわかりました。