11

2 つのオブジェクト (継承) を作成していますが、どちらも Base から継承しています。2 番目のオブジェクトのプロパティの割り当ては、最初のオブジェクトの値をオーバーライドします。

何かご意見は?基本クラスにその継承の子孫に共通のメンバーが含まれるように適切な継承を行う方法ですが、子孫は互いに干渉することなく独自の値を割り当てることができます。

var testParams1 = { title: "john" };
var testParams2 = { title: "mike" };

Function.prototype.inheritsFrom = function (baseClass)
{
    this.prototype = new baseClass;
    this.prototype.constructor = this;
    this.prototype.base = baseClass.prototype;
    return this;
};

function Base() {
    this.viewModel = {};
    this.viewModel.title = (function ()
    {
        var savedVal = "";
        return function (newVal)
        {
            if (typeof (newVal) === "undefined")
            {
                return savedVal;
            }
            savedVal = newVal;
        };
    })();
}
function Inherits(params) {
    this.viewModel.title(params.title);
}

Inherits.inheritsFrom(Base);

///// preparing code:
var testObj1 = new Inherits(testParams1);
var testObj2 = new Inherits(testParams2);

///// testing code:
equals(testObj1.viewModel.title(), testParams1.title, "first instance ok"); // returns "john"
equals(testObj2.viewModel.title(), testParams2.title, "second instance ok");  // also returns "john"
4

1 に答える 1

32

問題

  • Baseクラス コンストラクターは 1 回だけ呼び出されます。
    this.prototype = 新しい baseClass;
  • これらのメソッドはコンストラクター内で作成されるため (1 回だけ呼び出されます) 、特権メソッドはthisインスタンス間で同じオブジェクトを参照します。

意見の問題に基づく問題

  • Function.prototype所有していない JavaScript と一緒に作業する予定がある場合は、ネイティブ プロトタイプ (つまり ) を変更しないようにしてください。

解決

  • 作成された新しいインスタンスごとに、コンストラクターと親コンストラクターを呼び出します。
  • 親プロトタイプ チェーンを継承します (親クラスのインスタンスではありません)。
  • 作成されたインスタンス数とプロトタイプ チェーン内のコンストラクターの呼び出し数の 1:1 の比率を維持します。

マックスの問題の最終的な解決策

inherits機能とParentClass.call(this, title);ラインに特に注意してください。検索するコンストラクタはParentClassChildClass

/**
 * 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);
于 2013-01-29T05:30:28.817 に答える