3

// プロトタイプの継承

var AnswerPrototype = {
    constructor: function(value){
        this._val = value;
    },
    get: function(){
        return this._val;   
    }
}

var lifeAnswer = Object.create(AnswerPrototype);
lifeAnswer.constructor(100);
alert(lifeAnswer.get());

var desertAnswer = Object.create(AnswerPrototype);
desertAnswer.constructor(200);
alert(desertAnswer.get());

var firmAnswerProtoype = Object.create(AnswerPrototype);
firmAnswerProtoype.get = function(){
     return AnswerPrototype.get.call(this);   
}

var luckyAnswer = Object.create(firmAnswerProtoype);
luckyAnswer.constructor(1);
alert(luckyAnswer.get());

var magicAnswer = Object.create(firmAnswerProtoype);
magicAnswer.constructor(2);
alert(magicAnswer.get());

// 古典的な継承

function Answer(value){
    this._val = value;
}

Answer.prototype.get = function(){
     return this._val;   
}

var lifeAnswer = new Answer(100);
alert(lifeAnswer.get());

var desertAnswer = new Answer(200);
alert(desertAnswer.get());

function firmAnswer(value){
     return Answer.call(this,value);   
}

firmAnswer.prototype = Object.create(Answer);
firmAnswer.prototype.constructor = firmAnswer;

firmAnswer.prototype.get = function(){
    return Answer.prototype.get.call(this);   
}

var luckyAnswer = new firmAnswer(20);
alert(luckyAnswer.get())

2 番目が古典的で、1 番目が原型であることを誰か教えてください。私はhttp://www.objectplayground.com/を見ていましたが、私たちが使用する場合Object.create()とオブジェクトの場合の両方で完全に混乱していprototypeます。

4

3 に答える 3

2

まず、わかりやすくするために、Javascript にはプロトタイプの継承しかありません。あなたができることは、 「古典的な」継承をシミュレートすることです。この 2 つの違いは、オブジェクトがインスタンス化される構文に要約されます。「古典的な」継承では、より使い慣れたコンストラクタ関数と「新しい」演算子が使用されます。これにより、Javascript のオブジェクト作成および継承プロパティの固有のプロトタイプの性質が隠されます。

両方のケースを少し分解してみましょう。

var AnswerPrototype = {
   constructor: function(value){
      this._val = value;
   },
   get: function(){
      return this._val;   
   }
}

ここでのプロトタイプは、「コンストラクター」(または、より適切な名前の初期化関数) と共に明示的に作成されます。

var lifeAnswer = Object.create(AnswerPrototype);
lifeAnswer.constructor(100);
alert(lifeAnswer.get());

さて、ここでオブジェクトを作成するのは少し面倒です。最初に Object.create() を呼び出す必要があり、次に初期化関数を呼び出す必要があります。ただし、これは必ずしもそうである必要はありません。これは、両方を一度に実行する別のサンプル プロトタイプです。

var AnswerPrototype = {
   create: function(value){
      var obj = Object.create(AnswerPrototype);
      obj._val = value;
      return obj;
   },
   get: function(){
      return this._val;   
   }
}
var lifeAnswer = AnswerPrototype.create(100);

「古典的な」継承のシミュレートは、開発者がより使い慣れたコンストラクター関数と「新しい」演算子を使用してオブジェクトを作成できるようにすることに依存していますが、それは Javascript のプロトタイプの継承をマスクするだけなので、本質的に同じままです。

function Answer(value){
    this._val = value;
}

Answer.prototype.get = function(){
     return this._val;   
}

これは、Answer が暗黙的に作成されたプロトタイプ オブジェクト (Answer.prototype プロパティを介してアクセス可能) から分離されていることを除いて、プロトタイプの継承と大差ありません。

var lifeAnswer = new Answer(100);

実際には、砂糖var lifeAnswer = Object.create(Answer.prototype); // Call Answer on the newly created object to initialize some values, e.g. with Answer.call(lifeAnswer, 100);

firmAnswer.prototype = Object.create(Answer);
firmAnswer.prototype.constructor = firmAnswer;

firmAnswer.prototype は暗黙的に作成されたプロトタイプであり、最初のケースの farmAnswerPrototype と非常によく似ています。

特定の質問に答えるために、ここで Object.create() を使用する理由は、継承がnewすぐに非常に扱いにくくなるためです。次のようなことをする必要があります:

firmAnswer.prototype = new Answer();

ただしAnswer、空のコンストラクター ( function Answer() {}) にするか、引数なしで呼び出す (継承に使用する) か、引数付きで呼び出す ("Answer" オブジェクトのインスタンス化に使用する) かを明示的に区別する必要があります。

于 2013-08-14T12:38:45.107 に答える
1

あなたはそれらを後方に持っています。prototype2 つ目は、オブジェクトのプロパティを使用して継承するため、プロトタイプです。このブロック

firmAnswer.prototype = Object.create(Answer);
firmAnswer.prototype.constructor = firmAnswer;

firmAnswer.prototype.get = function(){
    return Answer.prototype.get.call(this);   
}

AnswerのインスタンスをfirmAnswerのプロトタイプに割り当てています。ただし、実際には継承を利用していないため、関数を再宣言しているため、これはお粗末なコードgetです。

私はこのコードを完全に避けます。2 つのタイプの違いについては、Crockford の The Good Parts をお読みください。

編集:(そのコードを参照せずに)少し説明すると、基本的な違いは次のとおりです。

Javascript での「古典的な」継承 (私が使用している方法) は、オブジェクトのプロパティをオーバーライドする場合です。fooとメソッドを持つオブジェクトがありますbar。次に、ライブラリ (jQuery や Prototype など) を使用してextendメソッドを呼び出します。このメソッドは、ベース オブジェクトと子オブジェクトの 2 つの引数を取ります。ベース オブジェクトのすべてのプロパティを取得し、子オブジェクトのプロパティを挿入して (場合によっては上書きします)、両方のプロパティが混在する新しいオブジェクトを返します。もう少しありますが、それが要点です。プロトタイプなしでオブジェクトのプロパティを操作しているだけです。

プロトタイプ継承は、Javascript の組み込みプロトタイプを使用します。プロトタイプは (本質的に) オブジェクトのチェーンです。A から継承するオブジェクト B があるとします。B から継承する C クラスを作成するには、C という名前の関数を作成し、B をプロトタイプに割り当てます。次に、C からプロパティが要求されると、Javascript は次のことを行います。

プロパティが C のインスタンスに存在するかどうかを確認します。そうでない場合:
プロパティが B のプロトタイプにあるかどうかを確認します。そうでない場合:
プロパティが A のプロトタイプにあるかどうかを確認します。そうでない場合:
エラーをスローします。

少し曖昧で申し訳ありません。私はそれを少し単純化しようとしています。Javascript のプロトタイプには多くの機能があります。Crockford の資料をいくつか読むことをお勧めします。

于 2013-08-14T12:27:15.470 に答える
1

2 番目がクラシックで、1 番目がプロトタイプである理由

どちらもプロトタイプの継承を使用しており、JavaScript にはクラスがありません。

2 番目のものは、クラス パターンを使用し、オブジェクトが演算子で作成されるときに従来のクラス構文 (Java で知られている) を模倣するため、「クラシック」(場合によっては「疑似クラシック」) と呼ばれますnew

唯一の違いは.prototype、コンストラクター関数からプロトタイプ オブジェクトへのリンクと、2 つではなく 1 つのコマンドだけを使用した短いインスタンス化構文です。背後で起こることは、両方のアプローチで同じです。

あなたの例でわかるように、2 つの「クラス」間の継承も少し異なります。どちらのアプローチでも、子のプロトタイプ オブジェクトは親のプロトタイプ オブジェクトから継承されます。また、どちらのアプローチでも、子インスタンスで関数を明示的に呼び出すことによって、親 (「スーパー」) メソッドを呼び出すことができます。それでも、「古典的な」パターンでは、子の新しいコンストラクター関数を宣言する必要があります(参照するため)が、明示的なプロトタイプのアプローチでは、子は親の.constructor メソッドを継承しています。

于 2013-08-14T12:37:45.880 に答える