JavaScript プロトタイプベース継承

概要: このチュートリアルでは、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 で参照できる匿名オブジェクトを提供します。

JavaScript Prototype

円は関数を表し、四角形はオブジェクトを表すことに注意してください。

person オブジェクトは、Object() 関数で参照される匿名オブジェクトへのリンクを持っています。[[Prototype]] は、リンクを表します。

JavaScript prototypal inheritance

つまり、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); // trueCode 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 DoeCode 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)

出力

trueCode language: JavaScript (javascript)

概要

  • 継承により、オブジェクトはコードを重複させることなく、別のオブジェクトのプロパティとメソッドを使用できます。
  • JavaScript はプロトタイプベース継承を使用します。
このチュートリアルは役に立ちましたか?