JavaScriptのプロトタイプベースのオブジェクト指向について、調べたこと
jsは(ES6より前は)クラスを持たないオブジェクト指向言語である。クラスの代わりに、プロトタイプというプロパティを作り、そのプロパティを複数のインスタンスで共有する。そのためプロトタイプベースのオブジェクト指向言語といわれている。
jsの全てのオブジェクト(関数やプロパティの集合)は、__proto__プロパティに「継承したオブジェクト」のメモリアドレスを格納できる。
jsの全てのオブジェクトは、Object.prototypeを継承している。そのため、__defineSetter__, __defineGetter__, toString, hasOwnPropertyなどのメソッドをデフォルトで使うことができる。 下記はコンソールログでオブジェクトを生成し、継承元のObject.prototypeを表示している。
コンストラクタ関数とnew演算子を使ったオブジェクト生成の例
js create object with new Object()
生成したオブジェクトの中身をコンソールで見てみよう!
chromeのコンソールログでまったく同じコードを入力する。
コンストラクタPersonから生成したperson1は、name, a, __proto__の3つのプロパティを持つ。__proto__プロパティには、コンストラクタ関数Personのprototypeのメモリアドレスを格納する。このメモリアドレスを元に、person1はコンストラクタ関数が持つoutputName()を使用することができる。
図で描くとこんな感じ。person1の__proto__にはPerson.prototypeのメモリアドレスが格納されており、Person.prototypeのプロパティの参照が可能である。
一方、person2が持つプロパティはnameと__proto__のみである。person2.aが定義されていない場合は、継承元である上位のPerson.prototypeを探索しに行く。もし見つからなければ最上位の Object.prototype までプロパティを探索しにいく。
オブジェクトの継承過程をたどる
Personコンストラクタから生成したオブジェクトperson1は、コンストラクタ関数とは別のメモリに格納される。オブジェクトによって、プロトタイプチェーンが異なる。
オブジェクトperson1は、下記のようになる。
person1 < Person < Object < null (上位の継承オブジェクトがない)
コンストラクタPersonは、下記のようになる。
Person < Empty < Object < null (上位の継承オブジェクトがない)
コンソールで見てみよう。
function Empty()のプロトタイプにはapplyやcallメソッドが定義されている。