概要: このチュートリアルでは、JavaScript のプロトタイプベース継承の仕組みを学びます。
JavaScript プロトタイプベース継承の紹介
Java や C++ など、他のオブジェクト指向プログラミング言語を扱ったことがある方は、継承の概念に馴染みがあるでしょう。
このプログラミングパラダイムでは、クラスはオブジェクトを作成するための設計図です。既存のクラスの機能を再利用する新しいクラスを作成したい場合は、既存のクラスを拡張する新しいクラスを作成できます。これは古典的継承と呼ばれます。
JavaScript は古典的継承を使用しません。代わりに、プロトタイプベース継承を使用します。
プロトタイプベース継承では、オブジェクトはプロパティを、プロトタイプのリンクを通じて別のオブジェクトから「継承」します。
JavaScript プロトタイプベース継承と __proto__
概念を明確にするために、例を見てみましょう。
以下は、person
オブジェクトを定義します。
let person = {
name: "John Doe",
greet: function () {
return "Hi, I'm " + this.name;
}
};
Code language: JavaScript (javascript)
この例では、person
オブジェクトはプロパティとメソッドを持っています。
name
は、人の名前を格納するプロパティです。greet
は、挨拶を文字列として返すメソッドです。
デフォルトでは、JavaScript エンジンは組み込みの Object()
関数と、Object.prototype
で参照できる匿名オブジェクトを提供します。
円は関数を表し、四角形はオブジェクトを表すことに注意してください。
person オブジェクトは、Object()
関数で参照される匿名オブジェクトへのリンクを持っています。[[Prototype]]
は、リンクを表します。
つまり、person
オブジェクトは、Object.prototype
で参照される匿名オブジェクトで定義された任意のメソッドを呼び出すことができます。
たとえば、以下は person
オブジェクトを介して toString()
メソッドを呼び出す方法を示しています。
console.log(person.toString());
Code language: JavaScript (javascript)
出力
[object Object]
Code language: JavaScript (javascript)
[object Object]
は、オブジェクトのデフォルトの文字列表現です。
person
を介して toString()
メソッドを呼び出すと、JavaScript エンジンは person
オブジェクトでそれを見つけることができません。したがって、プロトタイプチェーンをたどり、Object.prototype
オブジェクトでメソッドを検索します。
JavaScript エンジンは Object.prototype
オブジェクトで toString()
メソッドを見つけることができるため、toString()
メソッドを実行します。
person
オブジェクトのプロトタイプにアクセスするには、次のように __proto__
プロパティを使用できます。
console.log(person.__proto__);
Code language: JavaScript (javascript)
本番コードでは __proto__
プロパティを使用しないでください。デモンストレーションのみに使用してください。
以下は、person.__proto__
と Object.prototype
が同じオブジェクトを参照することを示しています。
console.log(person.__proto__ === Object.prototype); // true
Code language: JavaScript (javascript)
以下は、teach()
メソッドを持つ teacher
オブジェクトを定義します。
let teacher = {
teach: function (subject) {
return "I can teach " + subject;
}
};
Code language: JavaScript (javascript)
person
オブジェクトと同様に、teacher.__proto__
は、次の図に示すように Object.prototype
を参照します。
teacher
オブジェクトが person
オブジェクトのすべてのメソッドとプロパティにアクセスできるようにするには、teacher
オブジェクトのプロトタイプを person
オブジェクトに設定できます。以下はその方法です。
teacher.__proto__ = person;
Code language: JavaScript (javascript)
これで、teacher
オブジェクトは、プロトタイプチェーンを介して person
オブジェクトから name
プロパティと greet()
メソッドにアクセスできます。
console.log(teacher.name);
console.log(teacher.greet());
Code language: JavaScript (javascript)
出力
John Doe
Hi, I'm John Doe
Code language: JavaScript (javascript)
teacher
オブジェクトで greet()
メソッドを呼び出すと、JavaScript エンジンは最初に teacher
オブジェクトでそれを見つけます。
JavaScript エンジンは teacher
オブジェクトでメソッドを見つけることができないため、プロトタイプチェーンをたどり、person
オブジェクトでメソッドを検索します。JavaScript エンジンは person
オブジェクトで greet()
メソッドを見つけることができるため、メソッドを実行します。
JavaScript では、teacher
オブジェクトが person
オブジェクトのメソッドとプロパティを継承すると言います。この種の継承は、プロトタイプベース継承と呼ばれます。
ES5 でプロトタイプベース継承を実装する標準的な方法
ES5 は、Object.create()
メソッドを使用してプロトタイプベース継承を扱うための標準的な方法を提供しました。
現在では、より新しい ES6 の class
キーワードと extends
キーワードを使用して継承を実装する必要があります。はるかにシンプルです。
Object.create()
メソッドは、新しいオブジェクトを作成し、既存のオブジェクトを新しいオブジェクトのプロトタイプとして使用します。
Object.create(proto, [propertiesObject])
Code language: JavaScript (javascript)
Object.create()
メソッドは、2 つの引数を受け入れます。
- 最初の引数 (
proto
) は、新しいオブジェクトのプロトタイプとして使用されるオブジェクトです。 - 2 番目の引数 (
propertiesObject
) は、指定された場合、新しいオブジェクトの追加のプロパティを定義するオプションのオブジェクトです。
person
オブジェクトがあるとします。
let person = {
name: "John Doe",
greet: function () {
return "Hi, I'm " + this.name;
}
};
Code language: JavaScript (javascript)
以下は、person
オブジェクトの __proto__
を持つ空の teacher
オブジェクトを作成します。
let teacher = Object.create(person);
Code language: JavaScript (javascript)
その後、teacher
オブジェクトのプロパティを定義できます。
teacher.name = 'Jane Doe';
teacher.teach = function (subject) {
return "I can teach " + subject;
}
Code language: JavaScript (javascript)
または、以下の文でこれらの手順をすべて一度に実行できます。
let teacher = Object.create(person, {
name: { value: 'John Doe' } ,
teach: { value: function(subject) {
return "I can teach " + subject;
}}
});
Code language: JavaScript (javascript)
ES5 では、オブジェクトのプロトタイプを返す Object.getPrototypeOf()
メソッドも導入されました。例:
console.log(Object.getPrototypeOf(teacher) === person);
Code language: JavaScript (javascript)
出力
true
Code language: JavaScript (javascript)
概要
- 継承により、オブジェクトはコードを重複させることなく、別のオブジェクトのプロパティとメソッドを使用できます。
- JavaScript はプロトタイプベース継承を使用します。