プロトタイプとプロトタイプチェーン
プロトタイプとは?
ここでは JavaScript のプロトタイプ (prototype)というものについて説明します。
プロトタイプは、あるオブジェクトの機能を継承したり、同じクラスのオブジェクト間でプロパティを共有することを可能にするなど、 とても大切な役割を果たしています。
「プロトタイプ」というのは「クラス定義」のようなものです。これから作成されるオブジェクトに、どのようなメソッドを持たせるか決めることができます。
デフォルトの Prototype オブジェクト
コンストラクタが作成された時に、プロトタイプ・オブジェクトも作成されます。そして、コンストラクタの prototype プロパティにセットされます。
コンストラクタは、オブジェクトを作成して初期化するための関数オブジェクトです。詳しくは「コンストラクタ」をみてください。
コンストラクタにセットされたプロトタイプオブジェクトは、同じコンストラクタから作成されるオブジェクト全て共通に参照されます。
コンストラクタが異なれば、異なるプロトタイプオブジェクトを持ちます。
例えば、Personという名前のコンストラクタがあるとします。
function Person(name, age) {
this.name = name;
this.age = age;
}
Personコンストラクタが作成されると、 そのprototypeプロパティに、デフォルトの空のプロトタイプオブジェクトが作成されます。
プロトタイプオブジェクトは__proto__というプロパティを持っています。これはプロトタイプオブジェクトを関連付けするときに内部的に使われます。
Personのプロトタイプオブジェクトの __proto__プロパティは、Object オブジェクトのプロトタイプオブジェクトを指しています。これはランタイムによって自動的に作成されます。
Object オブジェクトのプロトタイプは、全てのオブジェクトに共通のメソッドなどが定義されていて、例えば toString関数などが含まれます。
メソッドの追加とプロトタイプ・チェーンの形成
さて、Personコンストラクタのプロトタイプオブジェクトに、fooメソッドを追加してみましょう。
Person.prototype.foo = function() {
console.log(`foo: ${this.name}(${this.age})`);
};
これで、プロトタイプオブジェクトにfooメソッドがセットされます。
このように、プロトタイプオブジェクトは「コンストラクタのprototypeプロパティ」「Personプロトタイプオブジェクト」 「Object プロトタイプオブジェクト」 という風に、数珠つなぎに参照を持っています。
これをプロトタイプ・チェーン (Prototype chain) といいます。
プロトタイプに作成したメソッドを呼ぶ
さて、コンストラクタが準備できたので、このPersonコンストラクタを使って、Personオブジェクトをひとつ作りましょう。
let p = new Person('Ichiro', 30);
p.foo();
作成された Person オブジェクトには、明示的には prototype プロパティというのはありません。上で出てきているprototypeプロパティは、コンストラクタ (広く言えば関数オブジェクト) のプロパティです。
しかしコンストラクタは、新しいオブジェクトに内部的に、プロトタイプオブジェクトへの参照を渡しています。
このため、作成されたオブジェクトから、プロトタイプ内に定義された関数を呼ぶことができるのです。
では、動作確認をしてみましょう。
// Person コンストラクタ
function Person(name, age) {
this.name = name;
this.age = age;
}
// コンストラクタの prototype に foo 関数を作成
Person.prototype.foo = function() {
console.log(`foo: ${this.name}(${this.age})`);
}
let p = new Person('Ichiro', 30);
p.foo(); // foo() の呼び出し
実行結果は次の通りです。
確かにfoo関数が実行できました。出力された内容から、コンストラクタで渡した値が、ちゃんと foo関数で使えていることがわかります。
ちなみに、ブラウザ (Chrome) のデバッグツールのコンソールにオブジェクトを表示してみると、次のようになります。
__proto__と表示されているところを辿ると、プロトタイプチェーンを確認することができます。
以上で プロトタイプ (Prototype) オブジェクトの基本的なことについて説明しました。 次の記事では、もう一歩進めて、Prototype オブジェクトを使って、オブジェクトの継承関係を実装する方法について説明します。