元の記事: JavaScript — Inheritance, delegation patterns and Object linking
著者: NC Patro
JavaScript(プロトタイプ継承)での継承、デリゲートパターン、および他のオブジェクトへのオブジェクトの関連付けの学習
継承とは#
ほとんどのクラスベースのオブジェクト指向言語では、継承は 1 つのオブジェクトが別のオブジェクトのすべてのプロパティとメソッドを取得できる仕組みです。ES2015
ではclass
キーワードが提案されましたが、JavaScript
はクラスベースの言語ではなく、本質的にはプロトタイプチェーンの方法です。
クラシック継承とプロトタイプ継承#
クラシック継承(非 JavaScript)#
Vehicle
は親クラスであり、v1
とv2
はVehicle
のインスタンスです。Car
はVehicle
のサブクラスであり、c1
とc2
はCar
のインスタンスです。- クラスを継承すると、クラシック継承では親クラスの振る舞いが子クラスにコピーされ、親子クラスは独立したエンティティになります。
- これは、車がツールと車の図面で作られるが、完成した後はそれぞれが独立した個体であるため、コピーされるために関連性がないため、すべての矢印が下向き(プロパティと振る舞いが下に伝播する)理由です。
プロトタイプ継承(デリゲートパターン)#
v1
とv2
はVehicle.prototype
に関連付けられています。これらはnewを使用して作成されたためです。- 同様に、
c1
とc2
はCar.prototype
に関連付けられ、Car.prototype
はVehicle.prototype
に関連付けられています。 JavaScript
では、オブジェクトを作成すると、プロパティや振る舞いをコピーするのではなく、リンクを作成します。クラスを継承する場合も同様のリンクが作成されます。- クラシックな非
JavaScript
の継承と比較して、すべてのリンクは逆方向に向かっているため、デリゲートリンクと呼ばれる行動委譲リンクです。これらのリンクはプロトタイプチェーンと呼ばれます。 - このパターンはデリゲートパターンと呼ばれ、一般的には
JavaScript
でのプロトタイプ継承として知られています。
詳細については、この記事JavaScript - プロトタイプを参照してください。
プロトタイプ継承の例#
Object.create()
を使用してクラシック継承を実装します。- 以下のコードスニペットでは、
Object.create()
関数のヘルプを使用してCar.prototype
とVehicle.prototype
を接続します。
// Vehicle - スーパークラス
function Vehicle (name) {
this.name = name;
}
// スーパークラスのメソッド
Vehicle.prototype.start = function () {
return "engine of " + this.name + " starting...";
}
// Car - サブクラス
function Car (name) {
Vehicle.call(this, name); // スーパークラスのコンストラクタを呼び出す
}
// サブクラスがスーパークラスを拡張
Car.prototype = Object.create(Vehicle.prototype);
// サブクラスのメソッド
Car.prototype.run = function () {
console.log("Hello " + this.start());
}
// サブクラスのインスタンス
var c1 = new Car("Fiesta");
var c2 = new Car("Baleno");
// サブクラスのメソッドで内部的にスーパークラスのメソッドにアクセスする
c1.run(); // "Hello engine of Fiesta starting..."
c2.run(); // "Hello engine of Baleno starting..."
- 上記のコードでは、以下のプロトタイプチェーンにより、オブジェクト
c1
はrun()
メソッドとstart()
メソッドにアクセスできることがわかります。次の図に示すように、c1
にはそのようなメソッドはありませんが、上にリンクがあります。 - 上記のコードの
this
は、各メソッドの現在の実行コンテキスト、つまりc1
とc2
です。
詳細については、この記事JavaScript-this と new についてのすべてを参照してください。
上記のコードの図解:
他のオブジェクトへの関連付け#
- ここでは、以前の継承の例コードを簡略化し、オブジェクト間のリンクに焦点を当てます。
- したがって、.prototype、constructor、およびnewキーワードを削除し、オブジェクトのみを考慮します。
Object.create()
関数を使用して関数間のすべてのリンクを作成します。
以下は、以前の例コードの簡略版です:
// 初期化メソッドを持つ基本オブジェクト
var Vehicle = {
init: function (name) {
this.name = name;
},
start: function () {
return "engine of " + this.name + "starting...";
}
}
// サブオブジェクトと基本オブジェクトの間に作成されたデリゲートリンク
var Car = Object.create(Vehicle);
// サブオブジェクトのメソッド
Car.run = function () {
console.log("Hello " + this.start());
};
// デリゲートリンクを持つインスタンスオブジェクトはサブオブジェクトを指します
var c1 = Object.create(Car);
c1.init('Fiesta');
var c2 = Object.create(Car);
c2.init('Baleno');
c1.run(); // "Hello engine of Fiesta starting..."
c2.run(); // "Hello engine of Baleno starting..."
上記のコードの図解:
- これで、new、すべての *.prototype*、コンストラクタ、およびメソッドの呼び出しの複雑さを排除し、同じ結果を実現できることがわかります。
- 唯一重要なのは、
c1
がオブジェクトにリンクし、別のオブジェクトにリンクし、それ以降も同様に続くことです。 - これはオブジェクトデリゲートパターンとも呼ばれます。
まとめ#
コード内でプロトタイプ継承とプロトタイプチェーンを使用する前に、それらを理解することは重要です。複雑さを回避するために。
参考文献: You Don't Know JS シリーズ