問題
Base
クラス コンストラクターは 1 回だけ呼び出されます。
this.prototype = 新しい baseClass;
- これらのメソッドはコンストラクター内で作成されるため (1 回だけ呼び出されます) 、特権メソッドは
this
インスタンス間で同じオブジェクトを参照します。
意見の問題に基づく問題
Function.prototype
所有していない JavaScript と一緒に作業する予定がある場合は、ネイティブ プロトタイプ (つまり ) を変更しないようにしてください。
解決
- 作成された新しいインスタンスごとに、コンストラクターと親コンストラクターを呼び出します。
- 親プロトタイプ チェーンを継承します (親クラスのインスタンスではありません)。
- 作成されたインスタンス数とプロトタイプ チェーン内のコンストラクターの呼び出し数の 1:1 の比率を維持します。
マックスの問題の最終的な解決策
inherits
機能とParentClass.call(this, title);
ラインに特に注意してください。検索するコンストラクタはParentClass
、ChildClass
/**
* Allows a child constructor to safely inherit the parent constructors prototype chain.
* @type {Function}
* @param {!Function} childConstructor
* @param {!Function} parentConstructor
*/
function inherits(childConstructor, parentConstructor){
var TempConstructor = function(){};
TempConstructor.prototype = parentConstructor.prototype; // Inherit parent prototype chain
childConstructor.prototype = new TempConstructor(); // Create buffer object to prevent assignments directly to parent prototype reference.
childConstructor.prototype.constructor = childConstructor; // Reset the constructor property back the the child constructor
};
//////////////////////////////////////
/** @constructor */
function ParentClass(title) {
this.setTitle(title);
var randId_ = Math.random();
/** @return {number} */
this.getPrivlegedRandId = function()
{return randId_;};
};
/** @return {string} */
ParentClass.prototype.getTitle = function()
{return this.title_;};
/** @param {string} value */
ParentClass.prototype.setTitle = function(value)
{this.title_ = value;};
//////////////////////////////////////
/**
* @constructor
* @param {string} title
* @param {string} name
*/
ChildClass = function (name, title) {
ParentClass.call(this, title); // Call the parent class constructor with the required arguments
this.setName(name);
}
inherits(ChildClass, ParentClass); // Inherit the parent class prototype chain.
/** @return {string} */
ChildClass.prototype.getName = function()
{return this.name_;};
/** @param {string} value */
ChildClass.prototype.setName = function(value)
{this.name_ = value;};
不思議な方向へ転がる
なぜそれが機能するのか、機能を単に覚えているのかに興味がある人向けinherits
です。
プロトタイプ チェーンを使用してプロパティを解決する方法
インスタンス レベルでプロパティが見つからない場合、JavaScript はインスタンス コンストラクターのプロトタイプ チェーンを検索して、不足しているプロパティを解決しようとします。プロパティが最初のプロトタイプ オブジェクトで見つからない場合は、親のプロトタイプ オブジェクトを検索し、同様に まで検索しObject.prototype
ます。範囲内で見つからない場合Object.prototype
、エラーがスローされます。
子コンストラクターから親コンストラクターを呼び出す: 試行 #1
// Bad
var ChildConstructor = function(arg1, arg2, arg3){
var that = new ParentConstructor(this, arg1, arg2, arg3);
that.getArg1 = function(){return arg1};
return that;
}
を使用して作成された変数はnew ChildConstructor
、 のインスタンスを返しますParentConstructor
。はChildConstructor.prototype
使用されません。
子コンストラクターから親コンストラクターを呼び出す: 試行 #2
// Good
var ChildConstructor = function(arg1, arg2, arg3){
ParentConstructor.call(this, arg1, arg2, arg3);
}
コンストラクターと親コンストラクターが適切に呼び出されるようになりました。ただし、コンストラクター内で定義されたメソッドのみが存在します。親プロトタイプのプロパティは、子コンストラクターのプロトタイプにまだリンクされていないため、使用されません。
親プロトタイプの継承: 試行 #1
// Bad
ChildConstructor.prototype = new ParentConstructor();
親コンストラクターは、使用されているかどうかに応じて、1 回だけ呼び出されるか、1 回だけ呼び出さParentConstructor.call(this)
れます。
親プロトタイプの継承試行 #2
// Bad
ChildConstructor.prototype = ParentConstructor.prototype;
これは技術的には機能しますが、オブジェクトはコピーではなく参照によって渡されるため、へのChildConstructor.prototype
割り当ても に割り当てられます。ParentConstructor.prototype
親プロトタイプの継承試行 #3
// Almost there
var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();
ChildConstructor.prototype
これは一時的な無名関数のインスタンスであるため、プロパティを割り当てることができます。のインスタンスで見つからないプロパティは、TempConstructor
そのプロパティのプロトタイプ チェーンをチェックするため、親プロトタイプが正常に継承されます。唯一の問題は、ChildConstructor.prototype.constructor
現在 を指していることTempConstructor
です。
親プロトタイプの継承試行 #4
// Good
var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();
ChildConstructor.prototype.constructor = ChildConstructor;
すべて一緒に
var ParentConstructor = function(){
};
var ChildConstructor = function(){
ParentConstructor.call(this)
};
var TempConstructor = function(){};
TempConstructor.prototype = ParentConstructor.prototype;
ChildConstructor.prototype = new TempConstructor();
ChildConstructor.prototype.constructor = ChildConstructor;
親クラスからの継承に成功しました! もっとうまくやれるか見てみましょう。
継承機能
function inherits(childConstructor, parentConstructor){
var TempConstructor = function(){};
TempConstructor.prototype = parentConstructor.prototype; // Inherit parent prototype chain
childConstructor.prototype = new TempConstructor(); // Create buffer object to prevent assignments directly to parent prototype reference.
childConstructor.prototype.constructor = childConstructor; // Reset the constructor property back the the child constructor (currently set to TempConstructor )
};
var ParentConstructor = function(){
};
var ChildConstructor = function(){
ParentConstructor.call(this)
};
inherits(ChildConstructor, ParentConstructor);