0
0

More than 1 year has passed since last update.

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

Last updated at Posted at 2021-10-23

prototypeについて

前回の記事で__proto__を利用することでgiraffのプロトタイプにanimal をセットしanimalのプロパティを見つけることができることが確認できました。(前回の記事)
しかし、コンストラクター関数を利用した別の方法で同じことを実現できます。

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

イラストにすると下記のようになります。
スクリーンショット 2021-10-23 20.38.40.png

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

JS
function Giraff() {}
console.log(Giraff.prototype.constructor === Giraff);// => true

スクリーンショット 2021-10-23 21.13.26.png

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

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
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
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

イラストで確認すると

スクリーンショット 2021-10-23 22.34.59.png

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

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

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

参考

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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0