プロトタイプベースとクラスベースの継承


208

JavaScriptでは、すべてのオブジェクトが同時にインスタンスとクラスになります。継承を行うには、任意のオブジェクトインスタンスをプロトタイプとして使用できます。

Python、C ++などでは、別々の概念としてクラスとインスタンスがあります。継承を行うには、基本クラスを使用して新しいクラスを作成する必要があります。新しいクラスを使用して、派生インスタンスを生成できます。

JavaScriptがこの方向に進んだのはなぜですか(プロトタイプベースのオブジェクト指向)?従来のクラスベースのオブジェクト指向オブジェクトに対するプロトタイプベースのオブジェクト指向オブジェクトの利点(および欠点)は何ですか?


10
JavaScriptは、プロトタイプ継承を備えた最初の言語であるSelfの影響を受けました。当時、古典的な継承は大流行で、最初にSimulaで導入されました。しかし、古典的な継承は複雑すぎました。その後、デビッドウンガーとランドールスミスは、GEBを読んだ後、ひらめきを示しました-「最も具体的なイベントは、イベントのクラスの一般的な例として役立ちます」。彼らは、クラスがオブジェクト指向プログラミングには必要ないことを理解しました。したがって、自己が生まれました。プロトタイプの継承が古典的な継承よりも優れていることを知るには、こちらをお読みください:stackoverflow.com/a/16872315/783743 =)
Aadit M Shah

@AaditMShah何/誰GEBですか?
Alex

3
@Alex GEBはDouglas Hofstadterによって書かれた本です。ゲーデルエッシャーバッハの略です。カート・ゲーデルは数学者でした。エッシャーは芸術家でした。バッハはピアニストでした。
Aadit M Shah 2016

回答:


201

ここには約100の用語の問題があり、そのほとんどは、自分のアイデアをThe Bestのように聞かせようとする誰か(あなたではない)を中心に構築されています。

すべてのオブジェクト指向言語は、いくつかの概念を処理できる必要があります。

  1. 特に、データメンバーおよびメンバー関数として、またはデータおよびメソッドとしてさまざまに知られている、データに関連する操作と共にデータのカプセル化。
  2. 継承、これらのオブジェクトはこれらの変更を除いて他のオブジェクトのセットと同じであると言う能力
  3. ポリモーフィズム(「多くの形状」)。実行するメソッドをオブジェクト自身が決定するため、言語に依存してリクエストを正しくルーティングできます。

さて、比較に関して:

まず最初に、「クラス」と「プロトタイプ」の質問全体を調べます。アイデアは当初Sim​​ulaで始まりました。クラスベースのメソッドでは、各クラスは同じ状態空間(「可能な値」を読み取る)と同じ操作を共有するオブジェクトのセットを表し、それによって等価クラスが形成されました。Smalltalkを振り返ってみると、クラスを開いてメソッドを追加できるため、これはJavaScriptでできることと実質的に同じです。

その後のオブジェクト指向言語は静的型チェックを使用できるようにしたかったので、コンパイル時に固定クラスセットの概念を取得しました。オープンクラスバージョンでは、柔軟性が向上しました。新しいバージョンでは、そうでなければテストが必要であったコンパイラで、ある種の正しさをチェックする機能がありました。

「クラスベース」の言語では、そのコピーはコンパイル時に行われます。プロトタイプ言語では、操作はプロトタイプデータ構造に格納され、実行時にコピーおよび変更されます。ただし、抽象的には、クラスは同じ状態空間とメソッドを共有するすべてのオブジェクトの同等クラスです。プロトタイプにメソッドを追加すると、効果的に新しい等価クラスの要素が作成されます。

さて、なぜそれをするのですか?これは主に、実行時にシンプルで論理的でエレガントなメカニズムを実現するためです。新しいオブジェクトを作成したり、新しいクラスを作成したりするには、ディープコピーを実行し、すべてのデータとプロトタイプデータ構造をコピーするだけです。継承とポリモーフィズムは多かれ少なかれ無料で得られます:メソッド検索は常に名前でメソッド実装のための辞書を要求することから成ります。

Javascript / ECMAスクリプトに終わった理由は、基本的に、10年前にこれを使い始めたときに、はるかに強力ではないコンピューターとはるかに洗練されていないブラウザーを扱っていたからです。プロトタイプベースの方法を選択すると、オブジェクトの向きの望ましいプロパティを維持しながら、インタープリターを非常にシンプルにすることができます。


1
そうですね、そのパラグラフは、私が別の意味であるかのように読みますか?DahlとNyqvistは、同じメソッドシグネチャを持つもののコレクションとして「クラス」を考え出しました。
チャーリーマーティン

1
その変化はそれがより良いと言っていますか?
チャーリーマーティン

2
申し訳ありませんが、CLOSは後半80年代からあるdreamsongs.com/CLOS.html 1980からSmalltalkのen.wikipedia.org/wiki/Smalltalk 1967年から1968年から完全なオブジェクト指向を持つとSimulaのen.wikipedia.org/wiki/Simula
チャーリーマーティン

3
@Stephano、それらはそれほど明確ではありません:Python、Ruby、Smalltalkはメソッド検索に辞書を使用し、javascriptとSelfはクラスを持っています。ある程度、違いはプロトタイプ指向言語がその実装を公開していることだけであると主張することができます。だから、それをビッグディールにしないのはおそらく良いことです:それはおそらくEMACSとviの間の議論のようです。
チャーリー・マーティン

21
役に立つ答え。+1コメント内のあまり役に立たないジャンク。つまり、CLOSとSmalltalkのどちらが最初だったのかが違いますか?ここのほとんどの人はとにかく歴史家ではありません。
Adam Arold、2013年

40

プロトタイプベースのアプローチにわずかに偏っている比較は、Self:The Power of Simplicityにあります。この論文では、プロトタイプを支持して次の議論を行っています。

コピーによる作成。プロトタイプから新しいオブジェクトを作成することは、単純な操作、つまり、単純な生物学的メタファーを使用した複製、複製によって行われます。クラスからの新しいオブジェクトの作成は、クラス内のフォーマット情報の解釈を含むインスタンス化によって行われます。インスタンス化は、計画から家を建てるのに似ています。コピーは、インスタンス化よりも単純な比喩として私たちにアピールします。

既存のモジュールの例。プロトタイプは、フォーマットや初期化の説明ではなくオブジェクトの例であるため、クラスよりも具体的です。これらの例は、ユーザーがモジュールを理解しやすくすることで再利用するのに役立ちます。プロトタイプベースのシステムにより、ユーザーは、その説明から意味を理解するように要求するのではなく、代表的な代表を調べることができます。

独自のオブジェクトのサポート。Selfは、独自の動作を持つ独自のオブジェクトを簡単に含めることができるフレームワークを提供します。各オブジェクトには名前付きスロットがあり、スロットは状態または動作を保持できるため、どのオブジェクトにも固有のスロットまたは動作を設定できます。クラスベースのシステムは、同じ動作をするオブジェクトが多数ある状況向けに設計されています。オブジェクトが独自の動作を実行するための言語的サポートはなく、インスタンスが1つだけであることが保証されているクラスを作成するのは厄介です[ シングルトンパターンを考える ]。自己はこれらの不利な点のどちらにも苦しんでいません。任意のオブジェクトを独自の動作でカスタマイズできます。一意のオブジェクトは一意の動作を保持でき、個別の「インスタンス」は必要ありません。

メタ回帰の排除。クラスベースのシステムのオブジェクトは、自給自足になることはできません。その構造と動作を表現するには、別のオブジェクト(そのクラス)が必要です。これは概念的に無限のメタ回帰につながりpointます:a はクラスPointのインスタンスであり、メタクラスのインスタンスですPoint metametaclassのインスタンスである、 Point、無限に。一方、プロトタイプベースのシステムでは、オブジェクトに独自の動作を含めることができます。そこに生命を吹き込むために他の物体は必要ありません。プロトタイプはメタ回帰を排除します。

自己はおそらくプロトタイプを実装する最初の言語です(JITのような他の興味深いテクノロジーも開拓しましたが、これは後にJVMに導入されました)。他のSelfのペーパーをことも有益です。


5
RE:メタ回帰の排除:クラスベースのCommon Lispオブジェクトシステムでは、a pointは、のインスタンスでPointあるmetaclassのインスタンスであるclass standard-classのインスタンスです。
Max Nanasy 2012

セルフペーパーへのリンクは死んでいます。実用的なリンク:自己:シンプルさの力 | 自己参考文献
user1201917

24

あなたは、チェックアウトする必要はJavaScriptに大きな本をDouglas Crockfordに。これは、JavaScriptクリエーターが行った設計上の決定のいくつかについて非常に良い説明を提供します。

JavaScriptの重要な設計面の1つは、そのプロトタイプの継承システムです。オブジェクトはJavaScriptのファーストクラスシチズンであるため、通常の関数もオブジェクト(正確には「関数」オブジェクト)として実装されます。私の意見では、元々はブラウザー内で実行するように設計されていたため、多数のシングルトンオブジェクトを作成するために使用することを意図していました。ブラウザのDOMでは、そのウィンドウ、ドキュメントなどすべてのシングルトンオブジェクトを見つけます。また、JavaScriptは緩やかに型付けされた動的言語です(厳密に型付けされた動的言語であるPythonとは対照的に)。その結果、「prototype」プロパティを使用してオブジェクト拡張の概念が実装されました。

したがって、JavaScriptで実装されているプロトタイプベースのオブジェクト指向には、いくつかの長所があると思います。

  1. 緩やかに型付けされた環境に適しています。明示的な型を定義する必要はありません。
  2. シングルトンパターンの実装が非常に簡単になります(この点でJavaScriptとJavaを比較してください。私が何を話しているかわかるでしょう)。
  3. 別のオブジェクトのコンテキストでオブジェクトのメソッドを適用する方法、オブジェクトから動的にメソッドを追加および置換する方法などを提供します(厳密に型指定された言語では不可能です)。

以下に、プロトタイプOOの短所をいくつか示します。

  1. プライベート変数を実装する簡単な方法はありません。クロージャーを使用したCrockfordの魔法使いを使用してプライベート変数を実装することが可能ですが、JavaやC#でプライベート変数を使用するほど簡単ではありません。
  2. JavaScriptで(その価値のために)多重継承を実装する方法はまだわかりません。

2
Pythonのように、プライベート変数には命名規則を使用するだけです。
aehlke

1
jsでプライベート変数を実行する方法はクロージャーであり、これは選択した継承タイプとは無関係です。
ベンジャ

6
Crockfordは、JavaScriptを損傷するために多くのことを行ってきました。かなり単純なスクリプト言語が、その内部の魅力的な魅力に変形されているからです。JSには真のプライベートキーワードスコープや真の多重継承はありません。それらを偽造しようとしないでください。
Hal50000 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.