2

codeacademyでの演習から:

function Penguin(name) {
    this.name = "Pingy";
    this.numLegs = 2;
}

// create your Emperor class here and make it inherit from Penguin
function Emperor (name){
    this.name = name;
}
Emperor.prototype = new Penguin();
var emp = new Emperor("Empy");

そこで、Emperorからプロパティを継承させました。これで2Penguinになることがわかりましたemp.numLegs

コメントを読んだ後、私は質問を編集しました。ご覧のとおり、作成時に名前を付けました。emp実際emp.name、新しいempの名前は「Empy」になります。しかしname、ペンギンクラスコンストラクターから継承されたものはどうですか?どこに行くの?

4

4 に答える 4

8

Codecademyは、初心者がJavaScriptを学ぶのに最適な方法です。プログラミング言語を学ぶには練習が必要であり、Codecademyはあなたに練習をさせます。

ただし、実践の範囲を超えて理論を学ぶ必要がある場合もあります。次の答えを読んでください。JavaScriptでのプロトタイプの継承を非常によく説明しています:https ://stackoverflow.com/a/8096017/783743

これでPenguin、次のようなコンストラクターができました。

function Penguin(name) {
    this.name = name;
    this.numLegs = 2;
}

次に、以下Emperorを継承するコンストラクターを作成しPenguinます。

function Emperor(name) {
    this.name = name;
}

Emperor.prototype = new Penguin();

Penguinのインスタンスを作成し、に割り当てていることに注意してくださいEmperor.prototype。したがって:

  1. Emperor.prototype.name = undefinedname-これは、コンストラクターに何も渡していないためですPenguin。私が書いEmperor.prototype = new Penguin("Empy")たとしたら、Emperor.prototype.nameそうなるでしょう"Empy"
  2. Emperor.prototype.numLegs = 2- 明らかに。

ここで、次のように新しいものを作成するときはEmperor、コンストラクターに名前を付ける必要があります(名前として継承undefinedしていることを忘れないでくださいPenguin)。したがって:

var emp = new Emperor("Empy");

それは昔ながらの方法でした。

現在、JavaScriptプログラマーは、別のコンストラクターを使用Object.createして継承しています。call例を挙げて説明しましょう。

function Emperor(name) {
    Penguin.call(this, name);
}

Emperor.prototype = Object.create(Penguin.prototype);
Emperor.prototype.constructor = Emperor;

この方法には、古い学校の方法に比べていくつかの利点があります。

  1. Penguinusingの新しいインスタンスを作成し、それにnew Penguin()引数を渡さない代わりに、usingのプロトタイプメンバーを継承PenguinObject.create(Penguin.prototype)ます。これにより、派生コンストラクターが実際に呼び出されるまで、基本コンストラクターの不要な初期化も防止されます。
  2. this.name = name派生コンストラクターに再度書き込む代わりに、それを使用して基本コンストラクターを呼び出しますPenguin.call(this, name)。このようなパターンはミックスインと呼ばれ、基本コンストラクターを実行時に初期化する必要がある場合、または独自の状態情報を維持する必要がある場合に非常に役立ちます。

追加のステートメントも追加したことに注意してくださいEmperor.prototype.constructor = Emperor。これはprototype、すべての関数に存在する非常に特殊なプロパティであるためです。constructorこれは、関数自体を指す非常に特殊なプロパティを持つオブジェクトを指します。Emperor.prototype他の何かに設定すると、このプロパティが失われます。したがって、再度設定します。

これらの両方の例の正味の効果は同じです。ただし、より複雑なコードの場合は、新しいメソッドを使用することをお勧めします。JavaScriptを楽しく学んでください。

于 2013-03-17T14:03:44.857 に答える
5

コンストラクターの内部にnameパラメーターとして指定する必要があるのはなぜか疑問に思っていると思います。Emperorthis.name = name;

JavaScriptでのプロトタイプの継承は非常に単純で、隠れた魔法はありません。Emperorとの間で提供した唯一の接続Penguinは、次の行にあります。

Emperor.prototype = new Penguin();

Emperor.prototypeはのインスタンスにPenguinなりましたが、それは任意のオブジェクトである可能性があります。関数Emperor関数について何も知らないPenguinので、魔法のようにを呼び出すことはありませんPenguin

Funcを使用して関数( )を呼び出すとnew、新しい空のオブジェクトが作成されます。そのプロトタイプは関数prototypeプロパティ(Func.prototype)です。このオブジェクトはthisコンストラクター内の値になり、他のオブジェクトが返されない場合は暗黙的に返されます。

しかし、Penguinクラスコンストラクターから継承された名前はどうでしょうか。どこに行くの?

これはのプロパティであり、各インスタンスのプロパティEmperor.prototypeによってシャドウされます。Emperorname

インスタンスとそのプロトタイプの関係を説明するいくつかの素晴らしいASCIIチャートを作成したここでの私の答えを見てください。


注: Emperor.prototype = new Penguin();実際には、継承を確立するための良い方法ではありません。 引数Penguin が必要な場合はどうなりますか?何が通過しますか?

現時点では、実際にはの新しいインスタンスを作成する必要はありません。プロトタイプチェーンPenguinに接続するだけです。あなたはこれを簡単に行うことができます:PenguinprototypeObject.create

Emperor.prototype = Object.create(Penguin.prototype);
Emperor.prototype.constructor = Emperor;

しかし、その場合、新しいEmperorオブジェクトにはnumLegsプロパティがなくなります。そのため、他の言語で:を使用する場合と同様に、Penguin新しいインスタンスごとにを呼び出す必要があります。Emperorsuper()

function Emperor (name){
    Penguin.call(this, name);
} 
于 2013-03-17T13:45:30.597 に答える
1

を呼び出すとnew Penguin()、このメソッドはオブジェクトを作成し、そのオブジェクトのプロトタイプを返します。

プロトタイプの継承を行う場合、最初に新しいPenguinオブジェクトを作成し、それらの値をのプロトタイプ内に配置するだけですEmperor。これで、新しいEmperorオブジェクトを作成するときに、プロトタイプはすでにの値に設定されていますPenguin。これらをオーバーライドするには、新しいコンストラクターでこれらを再度設定する必要があります。

JavaScriptの継承は、他の言語とは大きく異なります。

コード例:

function Penguin(name) {
    this.name = name;
    this.legs = 2;
}

function Emperor(name) {
    this.name = name;
}
Emperor.prototype = new Penguin();
/**
 * The prototype of Emperor now contains:
 * 
       {
           "name": undefined,
           "legs": 2
       }
 * 
 * Because you didn't add an argument to the constructor of `Penguin`
 */

var e = new Emperor('foo');
// The name property will get overriden with 'foo'
于 2013-03-17T13:52:21.130 に答える
1

オブジェクトを作成するPenguinときにも、パラメータに名前を渡す必要がありnameます。したがって、タイプの新しいオブジェクトを作成するときはPenguin、名前を渡す必要があります。同様にEmperor、オブジェクトから継承するPenguinため、コンストラクターで値を渡す必要があります。これにより、基本クラスで発生する処理とは異なる処理を実行する場合Penguinは、サブクラスコンストラクターでそのように定義できます。ただしEmperor、の定義に関する情報がないため、任意のタイプのオブジェクトオブジェクトにすることができますPenguin

クラス'Emperor'の定義で、行を削除した場合

 this.name = name;

次に、コンストラクターで任意の変数を渡しても、スーパーコンストラクターで定義されている値「Pingy」を取得できます。

行を追加すると

 Penguin.call(this, name) ;// As to call super class instance

numLegs次に、値を2として新しいオブジェクトに適切に渡します。

于 2013-03-17T13:53:32.967 に答える