JavaScriptのPrototypeについて

# 初めに
JavaScriptを勉強し始めてすぐ遭遇する概念ですが、なかなか全般的に理解できないのでそのまま放置してました。（読めるけどうまく使えなかった）最近もう一度JavaScriptを勉強することを機に、自分の言葉でわかりやすくまとめていきたいと思います。

まずはJavaScriptのオブジェクトは何？から始めたいと思います。
前に書いたものを振り返るとやっぱりあの頃の自分はまだ全般を理解していなかったと思った。例えば`typeof`運算子で`Array`が`object`だと疑問があったけど、自分の中は実践が大事だから使いこなせるまでそのまま疑問を放置してました。
でもこうして振り返りの大切さ、そしてやりがいも感じました。わからないことをわかるようになる楽しみを味わいながら頑張っていきたいと思います！

継承方法についてほかの文章：
[JavaScriptのinheritanceについて part1](https://qiita.com/hu-yu/items/13635160a4616d6d1c0d)
[JavaScriptのinheritanceについて part2](https://qiita.com/hu-yu/items/68c6eba22014b08d2d9d)

もう一度プロトタイプチェーンを考察した（相関図入り）：
[JavaScriptの.__proto__とprototypeとinstance](https://qiita.com/hu-yu/items/e1b7d59d9f406e73977b)


# Object in JavaScript

JavaScriptのデータ型は大きく分けると、プリミティブとオブジェクトがあります。

**Primitives**
`String`
`Number`
`BigInt`
`Boolean`
`undefined`
`Symbol`(ES6)
`null`
七つのプリミティブはimmutable（変わらない）、つまりstate（状態）が変更できないということです。変数に新しい値を代入することができるが、値自体を変更したわけではありません。（この部分は、自分は「利用してない値がメモリーリサイクルされる」と理解している）

**Object**
`Object`
`Array`
`Function`
`null`(the end of prototype chain)
そしてオブジェクトはJavaScriptの核心概念として、すべてのデータ型を格納するデータ型で、さらに細かく分けると`Array`、`Function`、`null`これらがオブジェクトのサブタイピングです。
そのなか`null`はプリミティブでありながら、すべての`Object.prototype`の原点（何も継承してないオブジェクト）でもあります。
```jsx
const x = {
  a: 1
}

console.log(x.__proto__ === Object.prototype) // true
console.log(x.__proto__.__proto__ === null) //true

console.log(Object.prototype.__proto__ === null) //true
console.log(Object.getPrototypeOf(Object.prototype)) // null
```
`Function`関数はオブジェクト？
少し変な言い方かもしれませんが関数はオブジェクトです。確かに`typeof`を使うと`function`という結果が出てきたんですが、JavaScriptの関数のなかには`[[Call]]`という隠しプロパティを持って、`callable object`（呼び出せるオブジェクト）として使えます。
```jsx
function callable() {
  const a = 1
}

callable.b = 2

console.log(callable.a) // undefined
console.log(callable.b) // 2

console.log(callable) // [Function: callable] { b: 2 }
console.log(callable.__proto__) // {}
console.log(callable.__proto__.__proto__ === Object.prototype) // true
console.log(callable.__proto__.__proto__.__proto__ === null) // true
```
`Function`は外部からアクセス不能という特性を持っていますが、オブジェクトのように`b`とその値を格納することができる。

実際ログしてみると`Function`の後ろにはオブジェクトがついていて`callable.b`によって値にアクセスできる。

また、`Object.prototype`のアクセサプロパティ`__proto__`を使って、関数の~~プロトタイプ~~`.__proto__`（参照先）は`{}`、順次に上にさかのぼると`Object.prototype`、`null`になります。

# Prototype in JavaScript
では`Prototype`、`Prototype Chain`は何でしょう？

`prototype`：原型。（複製元） [継承とプロトタイプチェーン](https://developer.mozilla.org/ja/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)

まずは`prototype`は原型という意味を持つ単語として、JavaScriptではプロパティやメソッドなどの元となるオブジェクトを`prototype`と言い、すべてのオブジェクトには必ず`prototype`が存在する。（`null`にはありません。）

## Prototypal Inheritance & Prototype Chain
**Inheritance**というのは継承です。`C++`、`C#`、`Java`では**Classical inheritance**、JavaScriptでは**Prototypal inheritance**を使用します。
[classical inheritance vs prototypal inheritance in javascript - stackoverflow](https://stackoverflow.com/questions/19633762/classical-inheritance-vs-prototypal-inheritance-in-javascript#:~:text=Classical%20inheritance%20is%20limited%20to,also%20objects%20inheriting%20from%20prototypes.)
[Master the JavaScript Interview: What’s the Difference Between Class & Prototypal Inheritance? - Eric Elliott](https://medium.com/javascript-scene/master-the-javascript-interview-what-s-the-difference-between-class-prototypal-inheritance-e4cd0a7562e9)

**Prototypal inheritance**を簡単に言うと、`prototype`はオブジェクトがほかのオブジェクトからプロパティやメソッドを直接継承する機能として、もともと持つものの上に、ほかの`prototype`と連携し拡張することができます。

自分のオブジェクトからプロパティを読み込んでも見つからなかった場合、自分の~~プロトタイプ~~`.__proto__`に読み込んでみる。それもなかった場合はさらに上、最後は必ず`null`にたどり着くので、すべての~~プロトタイプ~~`.__proto__`にはなかった場合は`undefined`を返します。これが**プロトタイプチェーン**です。

```jsx
let animal = {
  eats: true
}

let rabbit = {
  jumps: true
}

rabbit.__proto__ = animal

console.log(rabbit.jumps) // true
console.log(rabbit.eats) // true // get property from 'animal'

console.log(rabbit.__proto__) // { eats: true } // inherit from 'animal'
console.log(rabbit.__proto__.__proto__) // [Object: null prototype] {}
console.log(rabbit.__proto__.__proto__.__proto__) // null
console.log(rabbit.a) // undefined
```
（`.__proto__`の変更や使用は混乱を生じやすいので未推奨です。ここはただ説明の例として。）
[Prototypal inheritance - javascript.info](https://javascript.info/prototype-inheritance)

JavaScriptのメソッドもこの形式で利用されています。
[MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript)でメソッドを調べるときよく見てるけど気づかなかったところがあります。
メソッドを探すとき文字列なら`String.prototype.`、配列なら`Array.prototype.`から始まり、以前はただの分類だと思っていたが`prototype`を理解したら全部プロトタイプチェーンからメソッドを探し使っていることが分かりました。

ChromeのDevToolsで`[[Property]]`一覧表示できます。これで隠しプロパティ`[[Property]]`も見やすくなりますね。
![captures_chrome-capture-2022-6-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2477698/fbd55102-4cbc-ce35-230d-627be53b2391.png)

↓は別の例です。
```jsx
// Base object
const point2D = {
  x: 10,
  y: 20,
}

// Inherit from 'point3D' object
const point3D = {
  z: 30,
  __proto__: point2D,
}

console.log(
  point3D.x, // 10, inherited from point2D
  point3D.y, // 20, inherited from point2D
  point3D.z  // 30, from its own property
)
```
[Prototype - JavaScript. The Core: 2nd Edition](http://dmitrysoshnikov.com/ecmascript/javascript-the-core-2nd-edition/#prototype)

## .__ proto __
[Object.prototype.__ proto __ - MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/proto)
`.__proto__`はオブジェクト内部の`[[Property]]`プロパティとは同じではなく、`Object.prototype`のアクセサープロパティです。
今は非推奨になっているので、`Object.getPrototypeOf` と `Object.setPrototypeOf`関数の利用がおすすめです。
（ **[[Property]]** の直接変更はパフォーマンスに影響を及ぼすので避けた方がいいです。）

# Constructor Function & `new` vs. Prototype
`constructor`：コンストラクタ、構築子。 [Object.prototype.constructor - MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor)
**Constructor function（コンストラクタ関数）** というのは、普通の関数の内部に`this`でExecution Context（実行コンテキスト）を変えさせて、そして`new`で新しいインスタンスを創り出していく関数です。

**7/13補足：もう一度調べたらすべての関数には`constructor`プロパティを持ち、`new`でインスタンスを創るときに`constructor`プロパティで継承対象（親）を参照し、その親がコンストラクタ関数と呼びます。
この文章のコンストラクタ関数は特に`this`オブジェクトを所有するコンストラクタ関数を指しています。**

`new`で創られたインスタンスのコンテキストは、自分のスコープにバインドするようになります。
```jsx
function Cat(name, color) {
  this.name = name
  this.color = color
  this.species = 'cat'
  this.favorite = () => {
    console.log('eat and sleep')
  }
}

const cat1 = new Cat('Mio', 'white')
const cat2 = new Cat('Tora', 'orange')

console.log(cat1.name, cat1.color) // Mio white
console.log(cat2.name, cat2.color) // Tora orange

console.log(cat1.species) // cat
cat1.favorite() // eat and sleep
console.log(cat2.species) // cat
cat2.favorite() // eat and sleep
```
（コンストラクタ関数は頭文字が大文字という暗黙のルールがあります。）
初めて`console.log(cat1.name, cat1.color)`を読んだとき、多分私と同じ、なぜこれだけで値をアクセスできるの？って思っちゃいますね。

まず`function`は**callable object**として、別のところからの値を保存しアクセルすることもできます。`this`はここでの作用は指定された実行コンテキストで新しいオブジェクトを生成し値を保存する、ということで、オブジェクトのように値のアクセスができるわけです。なのでコンストラクタ関数には`this`で共有のオブジェクトでプロパティ（property name: property value）とメソッドを保存し、`new`ですべてのイスタンスが同じプロパティやメソッドが利用できるようになります。

[`this`のコンテキストについて](https://qiita.com/hu-yu/items/74529effd585de1d70ca)

しかしここには一つの問題があります。`new`で毎回新しいインスタンスを生成するたびに、中身が同じプロパティとメソッドを何度も複製していくということで、メモリーにとってデメリットになります。例えば`this.species`と`this.favorite()`には固定された内容には、何かメモリーにやさしい方法がないでしょうか。

実はJavaScriptではすべてのコンストラクタ関数に`prototype`プロパテ（オブジェクト）を持たされて、コンストラクタ関数で定義したプロパティやメソッドが、自分の`prototype`プロパティに所有し、そして`new`で創られたインスタンスたちは親であるコンストラクタ関数から`prototype`プロパティを継承する。

なので変わらない、あるいは変わる必要のないプロパティやメソッドをコンストラクタ関数の`prototype`オブジェクトに直接定義していいです。
```jsx
function Cat(name, color) {
  this.name = name
  this.color = color
}

Cat.prototype.species = 'cat'
Cat.prototype.favorite = () => {
  console.log('eat and sleep')
}
// console.log(Cat.prototype)
// { species: 'cat', favorite: [Function (anonymous)] }
```
ここから
**コンストラクタ関数とインスタンスの関連**、
**コンストラクタ関数がインスタンスの`prototype`であるかどうかの確認、**
**インスタンスのプロパティはコンストラクタ関数からどう継承してきたかの確認**、
...いくつのメソッド紹介したいと思います。

## `instanceof`
`instanceOf`を用いてコンストラクタ関数とインスタンスの関連を確認する。
```jsx
console.log(cat1 instanceof Cat) // true
console.log(cat2 instanceof Cat) // true
```
## `isPrototypeOf()`
`isPrototypeOf()`メソッドを用いて、親コンストラクタ関数の`prototype`オブジェクトとイスタンスの関連を確認できます。
```jsx
console.log(Cat.prototype.isPrototypeOf(cat1)) // true
console.log(Cat.prototype.isPrototypeOf(cat2)) // true
```

## `hasOwnProperty()`
すべてのイスタンスには`hasOwnProperty()`メソッドがあります。`hasOwnProperty()`メソッドはプロトタイプチェーンではなく自分のプロパティだけ検定するので、これであるプロパティが親コンストラクタ関数（ローカル）から継承したか、それとも親コンストラクタ関数の`prototype`オブジェクトから継承したかを確認できます。

```jsx
console.log(cat1.hasOwnProperty('name')) // true
console.log(cat1.hasOwnProperty('species')) // false
console.log(cat2.hasOwnProperty('favorite')) // false
```
（`'species'`、`'favorite'`いずれもコンストラクタ関数からではなく、`prototype`を経由して継承しているので`false`。）
## `in`
`hasOwnProperty()`とは逆に`in`は自身のプロパティだけでなくプロトタイプチェーンを全部チェックする。
```jsx
console.log('name' in cat1) // true
console.log('species' in cat1) // true
```

## constructor in instance?
よく間違われるところだと思いますが、実はインスタンスには`constructor`プロパティを所有しません。
```jsx
console.log(cat1.hasOwnProperty('constructor')) // false
console.log(cat1.__proto__.hasOwnProperty('constructor')) // true

console.log(cat1.constructor === Cat) // true
console.log(cat2.constructor === Cat) // true
```
`console.log(cat1.constructor === Cat)`が`true`なのは、インスタンスの`constructor`でなく、上のプロトタイプチェーンにコンストラクタ関数`Cat`がいるから、`Cat`の`constructor`と照らし合わせて自然と`true`が返されました。

インスタンスの`constructor`プロパティは可変です。コンストラクタ関数の`prototype`が変えてしまえば、新しいイスタンスの`constructor`も変えてしまいます。（古いのはpass by sharingの影響でそのままです。）

```jsx
Cat.prototype = {}
const cat3 = new Cat()
console.log(cat3.constructor === Cat) // false
console.log(cat3.constructor === Object) // true

console.log(cat1.constructor === Cat) // true
console.log(cat1.constructor === Object) // false
console.log(cat2.constructor === Cat) // true
console.log(cat2.constructor === Object) // false
// note: pass by sharing
```

# 参考資料まとめ
[Primitive (プリミティブ) - MDN](https://developer.mozilla.org/ja/docs/Glossary/Primitive)
[継承とプロトタイプチェーン - MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)
[Object.prototype.__ proto __ - MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/proto)
[Object.prototype.constructor - MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor)
[Object.getPrototypeOf() - MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf)
[Object.prototype.hasOwnProperty() - MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty)

[Prototype - JavaScript. The Core: 2nd Edition](http://dmitrysoshnikov.com/ecmascript/javascript-the-core-2nd-edition/#prototype)

[classical inheritance vs prototypal inheritance in javascript - stackoverflow](https://stackoverflow.com/questions/19633762/classical-inheritance-vs-prototypal-inheritance-in-javascript#:~:text=Classical%20inheritance%20is%20limited%20to,also%20objects%20inheriting%20from%20prototypes.)
[Master the JavaScript Interview: What’s the Difference Between Class & Prototypal Inheritance? - Eric Elliott](https://medium.com/javascript-scene/master-the-javascript-interview-what-s-the-difference-between-class-prototypal-inheritance-e4cd0a7562e9)
[Prototypal inheritance - javascript.info](https://javascript.info/prototype-inheritance)

# 感想
勉強メモとはいえ、公の場でいろんな方に見せるものでもありますので、正直外国人である自分の考えがうまく伝わったかどうかとても不安です。まだまだ初心者（学習歴8ヶ月）なのに、こういう角度でこうやって解釈していいのかなって文章を書くたびに思ってしまいます。でもやはりこれからもう一度振り返るときのために一度文章にする必要があると思います。
長文ですが、最後まで読んでいただきありがとうございます。お気づきの点がございましたら、ご指摘いただけると幸いです。