#prototypeについて
前回の記事で__proto__
を利用することでgiraffのプロトタイプにanimal をセットしanimalのプロパティを見つけることができることが確認できました。(前回の記事)
しかし、コンストラクター関数を利用した別の方法で同じことを実現できます。
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を確認しましょう。
今回Giraff.prototype = animal;と明示的にprototypeを指定してセットしましたが、デフォルトのprototypeはconstructor というプロパティだけを持つオブジェクトで、それは関数自体を指します。
function Giraff() {}
console.log(Giraff.prototype.constructor === Giraff);// => true
constructorプロパティを使って既存のものと同じコンストラクタを使って新しいオブジェクトを作成することができます。
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" はなくなります。
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ではこのような参照の仕組みをとっているんでしょうか。
その理由の一つとしてメモリの効率化が挙げられます。
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が出力されます。
イラストで確認すると
これをコンストラクター関数にlength関数をセットし作り直すと
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
イラストのようにインスタンスの生成ごとにlength関数を生成します。生成された関数は同じ参照先ではないので最後の出力は当然falseになります。
##参考
Udemy: 【JS】ガチで学びたい人のためのJavaScriptメカニズム
現代の JavaScript チュートリアル:https://ja.javascript.info/logical-operators