【俺的理解】JavaScriptのprototype
公開日:
参考記事
https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Object_prototypes
https://jsprimer.net/basic/prototype-object
https://qiita.com/saka212/items/e897af630a135981fbc3
プロトタイプとは
概要
JavaScript ですべてのオブジェクトは、そのプロトタイプと呼ばれる組み込みプロパティを持っています。プロトタイプはそれ自体がオブジェクトなので、プロトタイプは自分自身でプロトタイプを持ち、プロトタイプチェーンと呼ばれるものを持ちます。自分自身でプロトタイプに null を持つプロトタイプに到達すると、その連鎖は終わります。
https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Object_prototypes
プロトタイプは JavaScript
の全てのオブジェクトが持つ、組み込みのプロパティです。規定では、__proto__
というプロパティ名です。
試しにブラウザでログに出力してみても、空のオブジェクトを生成したつもりがプロトタイプというプロパティを持っていることがわかります。
そして、このプロトタイプには.__proto__
でアクセスできます。
要するに、JavaScript では全てのオブジェクトが自動的に__proto__
というプロパティを持ち、そのプロパティに設定されている値のことをそのオブジェクトのプロトタイプ
と呼ぶわけです。
じゃ、プロトタイプはどんな特徴を持つねん
詳細
プロトタイプがオブジェクトの特殊なプロパティだということは理解しました。次はその特徴を見ていきましょう。
簡単にいうと、
オブジェクトは外部から存在しないプロパティにアクセスされたとき、自身のプロトタイプに設定されているオブジェクトの中を探しにいきます。
そして、自身のプロトタイプにも存在しなかった場合、さらに自身のプロトタイプのプロトタイプ、さらにそのプロトタイプ、というように指定されたプロパティを探し、プロパティが存在した時点でその値を返します。プロトタイプがnull
になった時点で、プロパティの検索が終了し、全てのプロトタイプを探しても見つからない場合はundefined
を返します。
例
const user = {
name: '太郎',
};
オブジェクトを作って、user
という変数に格納しました。先ほど説明したように、自分で定義したわけではないですが、このオブジェクトはプロトタイプを持ちます。そして、JavaScript
ではオブジェクトを生成したときに自動的に Object.prototype
(詳細は後述)というオブジェクトがプロトタイプに設定されます。そして、Object.prototype
自身ののプロトタイプは null です。
このオブジェクトのtoString
メソッドを呼んでみましょう。もちろん自分ではtoString
というメソッドは定義していないのでメソッドが見つからずエラーになりそうですが、
console.log(user.toString()); // '[object Object]'
実際に呼び出すことが可能です。これはプロトタイプであるObject.prototype
オブジェクトにtoString
メソッドが定義されているから、呼び出すことができています。
次に、オブジェクトのhoge
プロパティにアクセスしてみましょう。
console.log(user.hoge); // undefined
undefined
が返ってきています。これは、オブジェクトにhoge
という名前のプロパティが存在せず、さらにObject.prototype
にも存在せず、Object.prototype
のプロトタイプがnull
なので検索が終了してundefined
が返ってきているわけです。
なんとなくつかめたでしょうか。言葉選びが難しいですが、クラスの『継承』のような特徴を持ちます。この特殊なプロトタイプというプロパティでの繋がりを『プロトタイプチェーン』と呼びます。
Object.prototype について
JavaScript でオブジェクトを生成した時に、デフォルトではObject.prototype
というオブジェクトがプロトタイプになります。
というかDate
オブジェクトなどもプロトタイプチェーンを辿ると最終的にObject.prototype
に辿り着きます。要するにObject.prototype
は、JavaScript において最も基礎的なオブジェクトです。始祖のオブジェクトです。Object.prototype
の詳細を探りましょう。
まず最初に、Object
は『関数』です。
console.log(typeof Object); // function
new
を用いてオブジェクトが生成できることから、コンストラクタ関数であることは想像できます。
const obj = new Object({});
https://ja.javascript.info/function-prototype
- 関数は
prototype
という特殊なプロパティを持つことができる。 - new 演算子とコンストラクタ関数を用いてオブジェクトを生成したとき、生成されたオブジェクトのプロトタイプになるのは、コンストラクタ関数の
prototype
オブジェクトに指定されているオブジェクトである。
これらがこのオブジェクトを理解する上でのポイントであり、結論です。
要するに、Object.prototype
はObject
という関数のprototype
というプロパティに設定されているただのオブジェクトです。
コンストラクターだのプロパティだのややこしいですが、Object.prototype
はただの『オブジェクト』です。
console.log(typeof Object.prototype); // 'object'
色々いじってみる
// 1つ目のオブジェクトを生成
// プロトタイプは指定していないので、デフォルトのObject.prototypeがプロトタイプになる
const fuga = {
fugafuga: 'fugafuga',
};
// 2つ目のオブジェクトを生成
// プロトタイプにはfugaを指定
const hoge = {
hogehoge: 'hogehoge',
__proto__: fuga,
};
// コンストラクタ関数を生成
function Piyo() {
this.piyopiyo = 'piyopiyo';
}
// コンストラクタ関数のプロトタイプにhogeを指定
Piyo.prototype = hoge;
// コンストラクタ関数からオブジェクトを生成
// コンストラクタ関数のプロトタイプがhogeなので生成されたオブジェクトのプロトタイプもhoge
const piyo = new Piyo();
// プロトタイプチェーンにより全てのプロパティにアクセスが可能
console.log(piyo.piyopiyo); // piyopiyo
console.log(piyo.hogehoge); // hogehoge
console.log(piyo.fugafuga); // fugafuga
console.log(piyo.toString()); // [object Object]
最後に
いっつも良くわかんねぇなぁって思いながら prototype の謎が解けました。
それと同時に、JavaScript は一見複雑なものでも、結局『オブジェクト』とかの単純なものにいくつくんだなぁと感じました。
では
Bye