JavaScript 入門 | オブジェクト (object) | プロトタイプ

継承 (inheritance)

継承 (inheritance) とは、新しいクラスで既存クラスのすべてのプロパティとメソッドを使用できることを意味する。

継承を通じて、新しいプログラムの要求に合わせて既存クラスを修正し、再利用できる。
また、クラス間の依存関係を形成することで、オブジェクトの関係を組織化できるという利点がある。
したがって、このような継承は抽象化、カプセル化とともに、オブジェクト指向プログラミングを構成する重要な特徴の 1 つである。

しかし C# や C++ のようなクラスベース (class-based) のオブジェクト指向言語とは異なり、JavaScript はプロトタイプベース (prototype-based) のオブジェクト指向言語である。
プロトタイプベースであるため、継承の概念はクラスベースのオブジェクト指向言語とは少し異なる。
JavaScript では、現在存在しているオブジェクトをプロトタイプとして使用し、そのオブジェクトを複製して再利用することを継承という。

プロトタイプ (prototype)

JavaScript のすべてのオブジェクトは、プロトタイプ (prototype) というオブジェクトを持っている。
すべてのオブジェクトは、それぞれのプロトタイプからプロパティとメソッドを継承する。
このように JavaScript のすべてのオブジェクトは、少なくとも 1 つ以上の別のオブジェクトから継承し、このとき継承される情報を提供するオブジェクトをプロトタイプという。

プロトタイプチェーン (prototype chain)

JavaScript では、オブジェクトイニシャライザーを使って作成された同じ型のオブジェクトは、すべて同じプロトタイプを持つ。
また、new 演算子を使って作成したオブジェクトは、コンストラクターのプロトタイプを自分のプロトタイプとして継承する。

var obj = new Object(); // このオブジェクトのプロトタイプは Object.prototype である。
var arr = new Array();  // このオブジェクトのプロトタイプは Array.prototype である。
var date = new Date();  // このオブジェクトのプロトタイプは Date.prototype である。

しかし Object.prototype オブジェクトはいかなるプロトタイプも持たず、どのプロパティも継承しない。
また、JavaScript に組み込まれたすべてのコンストラクターやユーザー定義コンストラクターは、このオブジェクトをプロトタイプとして持つ。

var date = new Date(); // このオブジェクトは Date.prototype だけでなく Object.prototype もプロトタイプとして持つ。

上のようにプロトタイプが継承される仮想的なつながりをプロトタイプチェーン (prototype chain) という。
Object.prototype オブジェクトは、このプロトタイプチェーンでも最上位に存在するプロトタイプである。
したがって、JavaScript のすべてのオブジェクトは Object.prototype オブジェクトをプロトタイプとして継承する。

プロトタイプの作成

プロトタイプを作成する最も基本的な方法は、オブジェクトコンストラクター関数 (object constructor function) を作成することである。
コンストラクター関数を作成し、new 演算子を使ってオブジェクトを作成すると、同じプロトタイプを持つオブジェクトを作成できる。

function Dog(color, name, age) { // 犬に関するコンストラクター関数を作成する。
    this.color = color;          // 色に関するプロパティ
    this.name = name;            // 名前に関するプロパティ
    this.age = age;              // 年齢に関するプロパティ
}
var myDog = new Dog("白色", "マル", 1); // このオブジェクトは Dog というプロトタイプを持つ。
document.write("我が家の犬は " + myDog.name + " という名前の、" + myDog.color + " の毛が魅力的な犬である。");

オブジェクトコンストラクター関数を作成するときは、慣例として名前の最初の文字だけを大文字にする。

オブジェクトにプロパティおよびメソッドを追加

すでに作成されたオブジェクトに新しいプロパティやメソッドを追加する方法は次のとおりである。

function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
}
var myDog = new Dog("白色", "マル", 1);
myDog.family = "シベリアンハスキー"; // 品種に関するプロパティを追加する。
myDog.breed = function() {           // 毛色を含む品種を返すメソッドを追加する。
    return this.color + " " + this.family;
}
document.write("我が家の犬は " + myDog.breed() + " である。");

上の例で新しく追加された family プロパティと breed() メソッドは、myDog インスタンスにだけ追加される。
すでに作成された別の Dog オブジェクトや、今後作成される他の Dog オブジェクトには追加されない。

プロトタイプにプロパティおよびメソッドを追加

プロトタイプに新しいプロパティやメソッドを追加する場合は、オブジェクトに追加するときとは別の方法を使用する必要がある。 プロトタイプの場合は、コンストラクター関数に直接追加してこそ、その後作成される他のすべてのオブジェクトにも適用できる。

function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
    this.family = "シベリアンハスキー"; // プロトタイプにプロパティを追加するときは基本値を持たせることができる。
    this.breed = function() {
        return this.color + " " + this.family;
    };
}
var myDog = new Dog("白色", "マル", 1);
var hisDog = new Dog("茶色", "コンイ", 3);
document.write("我が家の犬は " + myDog.family + " で、友人の家の犬も " + hisDog.family + " である。");

prototype プロパティ

prototype プロパティを利用すると、現在存在しているプロトタイプに新しいプロパティやメソッドを簡単に追加できる。

function Dog(color, name, age) {
    this.color = color;
    this.name = name;
    this.age = age;
}
// 現在存在している Dog プロトタイプに family プロパティを追加する。
Dog.prototype.family = "シベリアンハスキー";
// 現在存在している Dog プロトタイプに breed メソッドを追加する。
Dog.prototype.breed = function() {
    return this.color + " " + this.family;
};
var myDog = new Dog("白色", "マル", 1);
var hisDog = new Dog("茶色", "コンイ", 3);

document.write("我が家の犬は " + myDog.family + " で、友人の家の犬も " + hisDog.family + " である。");
document.write("我が家の犬の品種は " + myDog.breed() + " である。<br>");
document.write("友人の家の犬の品種は " + hisDog.breed() + " である。");

自分で作成したプロトタイプには、上のように新しいプロパティやメソッドを自由に追加または削除できる。
もちろん JavaScript 標準オブジェクトのプロトタイプも任意に修正できるが、重大なエラーが発生する可能性がある。
したがって JavaScript 標準オブジェクトのプロトタイプは修正してはならない。