プログラミングでは、何かの機能を取得しそれを引き継ぐような一連の作業がしばしば発生します。

JavaScriptはプロトタイプベースの言語と位置付けられているように、プロトタイプという仕組みを使って、基盤となる機能を他へと拡張していきます。

今回は、プロトタイプの仕組みについて解説していきます。

プロトタイプ

JavaScriptのオブジェクトは、prototypeと呼ばれる機能を引き継ぐためのオブジェクトを持っています。

例えば、メソッドを持つmemberというオブジェクトと、memberオブジェクトに少し変更を加えたgroupというオブジェクトを作りたいとします。
その際に一からgroupを作成するのではなく、memberが持つ機能を再利用し必要な箇所だけ変更を加えることで、groupオブジェクトを作ることができます。

prototype

このように、プロトタイプは実態のあるオブジェクトが他のオブジェクトへ機能を継承するような仕組みを持っています。

Objectはベースオブジェクト

JavaScriptのオブジェクトは、Prototypeという隠しプロパティを持っており、そのプロパティによって定義されたprototypeオブジェクトを継承しています。

その継承の元となっているのがObjectです。
Objectprototypeオブジェクトは、ArrayFunctionなどの他のオブジェクトで利用できるプロパティやメソッドを提供しています。

Object-prototype

このように、Objectがベースオブジェクトとなっています。

オブジェクトはどのように作られるのか

ここでは、オブジェクトはどのように作られているのか具体的に見ていきましょう。

以下は、オブジェクトリテラルで空のobjを定義しています。

let obj = {};

{}はリテラル表記であり、実態はnew Object()と同様です。

では、valueOfメソッドを使ってobjが持つプリミティブの値を確認してみます。

console.log(obj.valueOf()); // {}

すると、オブジェクトの空の値が返ってきます。

しかし、なぜオブジェクトリテラルで空のobjを定義しただけで、valueOfメソッドを呼び出すことができるのでしょうか。
それは、ObjectprototypeオブジェクトにこのvalueOfメソッドが定義されているからです。

試しに以下を行なってみます。

console.log(Object.prototype.valueOf); // "function"

すると、”function”が返ります。これは、ObjectprototypeオブジェクトにvalueOfメソッドが定義されているということです。

さらに、obj.valueOfObject.prototype.valueOfを比較してみます。

let obj = {};

console.log(obj.valueOf === Object.prototype.valueOf); // true

trueが返るように、2つは同等のものであることが分かります。
つまり、Objectのインスタンスであるobjは、Object.prototypeに定義されているメソッドやプロパティを継承しているということです。
そのことから、オブジェクトリテラルで作成したobjtoStringメソッドを使うことができたという訳です。

インスタンス化されたオブジェクトは、作成と同時にObject.prototypeオブジェクトに定義されているプロパティやメソッドを利用することができます。
このようなメソッド(プロパティ)のことをプロトタイプメソッド(プロパティ)と呼びます。

かんたんにまとめると、オブジェクトが作成される流れはこのようになります。

  1. オブジェクトリテラルやnew Objectでインスタンス化する
  2. Object.prototypeを確認する
  3. 2を継承し、新しいオブジェクトを作成する

まとめ

今回は、プロトタイプの仕組みについて解説しました。

// ポイント
* プロトタイプは、オブジェクトの作成時に自動的に作成される
* プロトタイプは、実態のあるオブジェクトから他のオブジェクトへ機能を継承する
* すべてのオブジェクトは、Prototypeという隠しプロパティを持っている
* Objectが他のオブジェクトのベースオブジェクトとなっている

JavaScriptでは、後に出てきたクラスがプロトタイプベースとして定義されているため、こまずはプロトタイプの仕組みを知っておくと良いでしょう。

合わせて読みたいプロトタイプシリーズ

第1回:プロトタイプの仕組み(当記事)
第2回:オブジェクトとプロトタイプ継承
第3回:プロトタイプとメソッド