Effective JavaScript Item 38は、サブコンストラクタ内で親構造関数を呼び出します.
3339 ワード
このシリーズはEffective JavaScriptの読書ノートとして使われています.
ゲームやグラフィックシミュレーションの応用には、シーンという概念があります.一つのシーンには一つのオブジェクトが含まれています.これらのオブジェクトはキャラクターと呼ばれています.各キャラクターは、そのタイプによって、一つの画像を表現するために使用されます.また、シーンも一つの下の図形表示オブジェクトの参照を保存する必要があります.コンテキストと呼ばれます.
SpaceShipタイプを確実にActorタイプのサブタイプにするためには、SpaceShipタイプのプロトタイプのオブジェクトもActorタイプのプロトタイプから引き継がなければなりません.これはES 5によって提供されるObject.create方法によって達成され得る(非ES 5の実装形態はItem 33を参照することができる).
親タイプのコンストラクタは、サブタイプのコンストラクタでのみ呼び出されますが、サブタイプのプロトタイプオブジェクトは、親タイプのプロトタイプから継承されたオブジェクトです.この点はサブタイプのプロトタイプを作成する際に注意が必要です.
サブタイププロトタイプオブジェクトの作成が完了すると、共通の属性と方法が設定されます.
締め括りをつける
サブタイプのコンストラクタにおいて父タイプのコンストラクタを呼び出し,thisの指向性を明示的に伝えた.Object.create法を使用して、親タイプの構造関数への呼び出しを避けるために、サブタイプのプロトタイプのオブジェクトを作成します.
ゲームやグラフィックシミュレーションの応用には、シーンという概念があります.一つのシーンには一つのオブジェクトが含まれています.これらのオブジェクトはキャラクターと呼ばれています.各キャラクターは、そのタイプによって、一つの画像を表現するために使用されます.また、シーンも一つの下の図形表示オブジェクトの参照を保存する必要があります.コンテキストと呼ばれます.
function Scene(context, width, height, images) {
this.context = context;
this.width = width;
this.height = height;
this.images = images;
this.actors = [];
}
Scene.prototype.register = function(actor) {
this.actors.push(actor);
};
Scene.prototype.unregister = function(actor) {
var i = this.actors.indexOf(actor);
if (i >= 0) {
this.actors.splice(i, 1);
}
};
Scene.prototype.draw = function() {
this.context.clearRect(0, 0, this.width, this.height);
for (var a = this.actors, i = 0, n = a.length; i < n; i++) {
a[i].draw();
}
};
シーン中のすべてのキャラクターは一つのベースから継承されます.このベースはすべてのキャラクターが持つ属性と方法を抽象化するために使用されます.例えば、各キャラクターオブジェクトはその場所の引用、座標情報を保存します.function Actor(scene, x, y) {
this.scene = scene;
this.x = x;
this.y = y;
scene.register(this);
}
同様に、Actorタイプのprototypeオブジェクトに共通の方法を定義します.Actor.prototype.moveTo = function(x, y) {
this.x = x;
this.y = y;
this.scene.draw();
};
Actor.prototype.exit = function() {
this.scene.unregister(this);
this.scene.draw();
};
Actor.prototype.draw = function() {
var image = this.scene.images[this.type];
this.scene.context.drawImage(image, this.x, this.y);
};
Actor.prototype.width = function() {
return this.scene.images[this.type].width;
};
Actor.prototype.height = function() {
return this.scene.images[this.type].height;
};
キャラクターベースがあれば、その上に具体的なタイプを作ることができます.例えば、宇宙船(SpaceShip)のキャラクターを作ると、こうなります.function SpaceShip(scene, x, y) {
Actor.call(this, scene, x, y);
this.points = 0;
}
SpaceShipの例もすべてのキャラクターにあるべき属性を持つことができるようにするために、SpaceShipの構造関数の体内で最初に親類(Actor)の構造関数を呼び出し、次にSpaceShipインスタンス自体の属性を初期化します.SpaceShipタイプを確実にActorタイプのサブタイプにするためには、SpaceShipタイプのプロトタイプのオブジェクトもActorタイプのプロトタイプから引き継がなければなりません.これはES 5によって提供されるObject.create方法によって達成され得る(非ES 5の実装形態はItem 33を参照することができる).
SpaceShip.prototype = Object.create(Actor.prototype);
SpaceShipのprototypeオブジェクトがActorの構造関数を呼び出して得られた場合、一連の問題が発生します.SpaceShip.prototype = new Actor();
Actorコンストラクタを呼び出したときには、合理的なパラメータが入力されませんでした.Actorは、シーンオブジェクトと座標情報をパラメータとして受け入れるため、SpaceShipタイプのプロトタイプのオブジェクトは、SpaceShipタイプの中のいくつかの共通の属性と方法を格納するためであり、明らかに、シーンと座標情報は、SpaceShipインスタンスによって異なり、これらの情報をprototypeオブジェクトに置くのは不適切である.親タイプのコンストラクタは、サブタイプのコンストラクタでのみ呼び出されますが、サブタイプのプロトタイプオブジェクトは、親タイプのプロトタイプから継承されたオブジェクトです.この点はサブタイプのプロトタイプを作成する際に注意が必要です.
サブタイププロトタイプオブジェクトの作成が完了すると、共通の属性と方法が設定されます.
SpaceShip.prototype.type = "spaceShip";
SpaceShip.prototype.scorePoint = function() {
this.points++;
};
SpaceShip.prototype.left = function() {
this.moveTo(Math.max(this.x - 10, 0), this.y);
};
SpaceShip.prototype.right = function() {
var maxWidth = this.scene.width - this.width();
this.moveTo(Math.min(this.x + 10, maxWidth), this.y);
};
この場合、Actorタイプ、SpaceShipタイプおよびそれらのprototypeオブジェクトの関係は以下の通りです.締め括りをつける
サブタイプのコンストラクタにおいて父タイプのコンストラクタを呼び出し,thisの指向性を明示的に伝えた.Object.create法を使用して、親タイプの構造関数への呼び出しを避けるために、サブタイプのプロトタイプのオブジェクトを作成します.