web-dev-qa-db-ja.com

プロトタイプの継承は、古典的な継承と実際にどのように異なりますか?

継承、ポリモーフィズム、およびカプセル化は、OOPの3つの最も明確で重要な機能であり、それらから、継承は最近、高い使用統計を持っています。私はJavaScriptを学んでおり、ここではすべてプロトタイプの継承があると言われ、世界中の人々はそれが何かはるかに異なる古典的な継承とは違うと言います。

ただ、実用的な点からどう違うのかわかりません。つまり、基本クラス(プロトタイプ)を定義し、そこからいくつかのサブクラスを派生させると、どちらも基本クラスの機能にアクセスでき、派生クラスの関数を拡張できます。私が言ったことを継承の意図した結果であると考える場合、プロトタイプバージョンとクラシックバージョンのどちらを使用しているかに注意する必要があるのはなぜですか。

もっと自分を明確にするために、私はプロトタイプとクラシックの継承の有用性と使用パターンに違いがないと思います。その結果、両者が同じものであるOOADになるため、それらが異なる理由を学ぶことに興味がなくなります。実際には(理論的にではなく)プロトタイプの継承は古典的な継承とどのように異なりますか?

27
Saeed Neamati

JS OOに関する最近のブログ投稿

あなたの比較はclassical OO JavaScriptでのエミュレーションclassical OO)だと思いますそしてもちろん、違いはわかりません。

免責事項:「プロトタイプOO」へのすべての参照を「プロトタイプOO)」に置き換えます。自己またはその他の実装の詳細。

ただし、プロトタイプOOは異なります。プロトタイプではオブジェクトのみがあり、オブジェクトを他のオブジェクトのプロトタイプチェーンに挿入することしかできません。オブジェクトのプロパティにアクセスするたびに、そのオブジェクトとプロトタイプチェーン。

プロトタイプの場合OOカプセル化の概念はありません。カプセル化はスコープ、クロージャ、ファーストクラス関数の機能ですが、プロトタイプOOとは関係ありません。継承の概念もありません。 「継承」とは、実際には単なるポリモーフィズムです。

ただし、ポリモーフィズムはあります。

例えば

var Dog = {
  walk: function() { console.log("walks"); }
}

var d = Object.create(Dog);
d.walk();

明らかにdはメソッドDog.walkにアクセスでき、これは多態性を示します。

したがって、実際には大きな違いがあります。ポリモーフィズムしかありません。

ただし、前述のように、そうしたい場合(なぜそうするのかわからない)、JavaScriptをエミュレートできますOOそして、(制限された)カプセル化と継承にアクセスできます。

6
Raynos

従来の継承は、状態なしで、親クラスから動作を継承します。オブジェクトがインスタンス化された瞬間の動作を継承します。

プロトタイプの継承は、親オブジェクトから動作と状態を継承します。オブジェクトが呼び出されたときの動作と状態を継承します。親オブジェクトが実行時に変更されると、子オブジェクトの状態と動作が影響を受けます。

プロトタイプ継承の「利点」は、すべてのオブジェクトがインスタンス化された後に状態と動作を「パッチ」できることです。たとえば、Ext JSフレームワークでは、フレームワークがインスタンス化された後、フレームワークのコアコンポーネントにパッチを適用する「オーバーライド」をロードするのが一般的です。

15
Joeri Sebrechts

まず、ほとんどの場合、オブジェクトを定義するのではなく使用します。オブジェクトの使用は、両方のパラダイムで同じです。

2つ目:ほとんどのプロトタイプ環境では、クラスベースの環境と同じ種類の分割が使用されます。つまり、メソッドは継承され、インスタンス上の可変データです。そのため、違いはほとんどありません。 ( このスタックオーバーフローの質問に対する私の回答 を参照してください。そして Self Paperクラスなしのプログラムの編成Citeseer for a PDF version を参照してください。)

3番目:JavaScriptの動的な性質は、継承の種類よりもはるかに大きな影響を与えます。タイプのすべてのインスタンスに新しいメソッドを追加できるのは、ベースオブジェクトに割り当てることでわかりますが、Rubyではクラスを再度開くことで同じことができます。

第4:newの使用を忘れることの実際的な問題ははるかに大きい一方で、実用的な違いは小さいです。つまり、newを欠落することで、あなたよりもはるかに影響を受けやすくなります。プロトタイプコードとクラシックコードの違いの影響を受けます。

とはいえ、プロトタイプ継承とクラシック継承の実際的な違いは、保持するメソッド(クラス)は保持するデータ(インスタンス)と同じであることです。これは、クラスを構築できることを意味します。少しずつ、インスタンスで使用するのと同じオブジェクト操作ツールをすべて使用します。 (これは、実際には、すべてのクラスエミュレーションライブラリがどのように行うかです。他の方法ではないようなアプローチについては、 Traits.js を参照してください)。これは、主にメタプログラミングをしている場合に役立ちます。

9
Sean McMillan

JavaScriptでのプロトタイプの継承は、以下の重要な点でクラスとは異なります。

コンストラクタは、newなしで呼び出すことができる単純な関数です。

function Circle (r, x, y) { 
  //stuff here
}
Var c = new Circle();
Circle.call(c, x, y, z); //This works and you can do it over and over again.

プライベート変数やメソッドはありません。せいぜいこれを行うことができます:

function Circle (r, x, y) {
  var color = 'red';
  function drawCircle () {
    //some code here with x, y and r
  }
  drawCircle();
  this.setX = function (x_) {
    x = x_;
    drawCircle();
  }

}
Circle.prototype.getX = function () {
   //Can't access x!
}

前の例では、偽のプライベート変数とメソッドに頼っていると、クラスを有意義に拡張できません。さらに、宣言したパブリックメソッドは、新しいインスタンスが作成されるたびに再作成されます。

0
Bjorn