JavaScriptのプロトタイプ継承について(2)

#prototypeについて
前回の記事で`__proto__`を利用することでgiraffのプロトタイプにanimal をセットしanimalのプロパティを見つけることができることが確認できました。([前回の記事](https://qiita.com/tomoki12/items/ee88145e3f3ff92ba45a）))
しかし、コンストラクター関数を利用した別の方法で同じことを実現できます。

```JS:JS
let animal = {
    eats: true
};
// let giraff = {
//     neck: "long"
// };

function Giraff(length) {
    this.neck = length
}

Giraff.prototype = animal;

let giraff = new Giraff('long') // giraff.__proto__ = animal;

console.log(giraff.neck); // =>long
console.log(giraff.eats); // =>true
```
コンストラクター関数がオブジェクト型の値をもつprototypeプロパティを持っている場合、new演算子は新しいオブジェクト（インスタンス）に対してそれを [[Prototype]] にセットします。
上記の例ですと、Giraff.prototype = animal;でanimalオブジェクトをprototypeプロパティにセットしています。したがってインスタンス化する時に[[Prototype]]にanimalをセットしています。giraffを確認しましょう。![スクリーンショット 2021-10-23 20.22.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1265227/26eb3035-78d0-afa5-093e-e495cd0a8c1f.png)

イラストにすると下記のようになります。
![スクリーンショット 2021-10-23 20.38.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1265227/abd50704-64d4-678d-dc20-100fc7683d93.png)

今回Giraff.prototype = animal;と明示的にprototypeを指定してセットしましたが、デフォルトのprototypeはconstructor というプロパティだけを持つオブジェクトで、それは関数自体を指します。

```JS:JS
function Giraff() {}
console.log(Giraff.prototype.constructor === Giraff);// => true
```
![スクリーンショット 2021-10-23 21.13.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1265227/fe5d38fe-4b96-3ee4-5827-2e02c07ed3ad.png)

constructorプロパティを使って既存のものと同じコンストラクタを使って新しいオブジェクトを作成することができます。

```JS:JS
function Giraff(neck) {
    this.neck = neck;
    console.log(neck);
}
let giraff = new Giraff("long");
let giraff2 = new giraff.constructor("short");

console.log(Giraff === giraff.constructor); // => true
```
もしデフォルトプロトタイプ全体を置き換えると、その中に "constructor" はなくなります。

```JS:JS
function Giraff(neck) {
    this.neck = neck;
    console.log(neck);
}

Giraff.prototype = {
    eats: true
};// => prototypeの上書き

let giraff = new Giraff("long");
  
console.log(Giraff === giraff.constructor);// => false
```

#prototypeのメリット
ところでなぜjavascriptではこのような参照の仕組みをとっているんでしょうか。
その理由の一つとしてメモリの効率化が挙げられます。

```JS:JS
function Giraff(name, neck) {
    this.name = name;
    this.neck = neck;
    
}

Giraff.prototype.length = function(){
    console.log(`${this.name} is ${this.neck}`);
}

const a = new Giraff('a', 'long')
const b = new Giraff('b', 'short')
a.length(); // =>a is long
b.length(); // =>b is short
console.log(a.length === b.length);// => true
```

今、Giraffのコンストラクター関数にlength関数をセットしそれぞれのインスタンスは[[Prototype]]にlength関数（実行可能なオブジェクト）が渡ります。参照先length関数は同じなので最後の行ではtrueが出力されます。
![スクリーンショット 2021-10-23 21.57.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1265227/3d8a734e-10d6-5e53-1b53-7dcfb08150d3.png)

イラストで確認すると

![スクリーンショット 2021-10-23 22.34.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1265227/1a342811-2f7a-2146-b853-01dff8147466.png)

これをコンストラクター関数にlength関数をセットし作り直すと

```JS:JS
function Giraff(name, neck) {
    this.name = name;
    this.neck = neck;
    this.length = function(){
        console.log(`${this.name} is ${this.neck}`)
    };
}

// Giraff.prototype.length = function(){
//     console.log(`${this.name} is ${this.neck}`);
// }

const a = new Giraff('a', 'long')
const b = new Giraff('b', 'short')
a.length();
b.length();
console.log(a.length === b.length);// => false
```
![スクリーンショット 2021-10-23 22.45.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1265227/7cc71610-4c1f-ccb9-3913-826fa2a6e6b7.png)

イラストのようにインスタンスの生成ごとにlength関数を生成します。生成された関数は同じ参照先ではないので最後の出力は当然falseになります。




##参考
Udemy： 【JS】ガチで学びたい人のためのJavaScriptメカニズム
現代の JavaScript チュートリアル:https://ja.javascript.info/logical-operators