Also hörte ich all die Jahre endlich auf, meine Füße zu schleppen und beschloss, JavaScript "richtig" zu lernen. Eines der am meisten kratzenden Elemente des Sprachdesigns ist die Implementierung der Vererbung. Nachdem ich Erfahrung mit Ruby hatte, freute ich mich sehr über Schließungen und dynamisches Tippen. Aber für mein Leben kann ich nicht herausfinden, welche Vorteile Objektinstanzen haben, wenn andere Instanzen für die Vererbung verwendet werden.
271
Antworten:
Ich weiß, dass diese Antwort 3 Jahre zu spät ist, aber ich denke wirklich, dass die aktuellen Antworten nicht genügend Informationen darüber liefern, wie die prototypische Vererbung besser ist als die klassische Vererbung .
Schauen wir uns zunächst die häufigsten Argumente an, die JavaScript-Programmierer zur Verteidigung der prototypischen Vererbung angeben (ich nehme diese Argumente aus dem aktuellen Antwortpool):
Jetzt sind alle diese Argumente gültig, aber niemand hat sich die Mühe gemacht, zu erklären, warum. Es ist, als würde man einem Kind sagen, dass es wichtig ist, Mathematik zu lernen. Sicher ist es das, aber das Kind kümmert sich bestimmt nicht darum; und man kann ein Kind nicht wie Mathe machen, wenn man sagt, dass es wichtig ist.
Ich denke, das Problem mit der prototypischen Vererbung ist, dass sie aus der Perspektive von JavaScript erklärt wird. Ich liebe JavaScript, aber die prototypische Vererbung in JavaScript ist falsch. Im Gegensatz zur klassischen Vererbung gibt es zwei Muster der prototypischen Vererbung:
Leider verwendet JavaScript das Konstruktormuster der prototypischen Vererbung. Dies liegt daran, dass Brendan Eich (der Schöpfer von JS) bei der Erstellung von JavaScript wollte, dass es wie Java aussieht (das klassische Vererbung hat):
Dies ist schlecht, da Benutzer bei der Verwendung von Konstruktoren in JavaScript an Konstruktoren denken, die von anderen Konstruktoren erben. Das ist falsch. Bei der prototypischen Vererbung erben Objekte von anderen Objekten. Konstruktoren kommen nie ins Bild. Das ist es, was die meisten Menschen verwirrt.
Menschen aus Sprachen wie Java, die klassische Vererbung haben, werden noch verwirrter, weil Konstruktoren zwar wie Klassen aussehen, sich aber nicht wie Klassen verhalten. Wie Douglas Crockford feststellte:
Hier hast du es. Direkt aus dem Maul des Pferdes.
Echte prototypische Vererbung
Bei der prototypischen Vererbung dreht sich alles um Objekte. Objekte erben Eigenschaften von anderen Objekten. Das ist alles dazu. Es gibt zwei Möglichkeiten, Objekte mithilfe der prototypischen Vererbung zu erstellen:
Hinweis: JavaScript bietet zwei Möglichkeiten zum Klonen eines Objekts: Delegierung und Verkettung . Von nun an verwende ich das Wort "Klon", um sich ausschließlich auf die Vererbung durch Delegierung zu beziehen, und das Wort "Kopieren", um sich ausschließlich auf die Vererbung durch Verkettung zu beziehen.
Genug Gerede. Sehen wir uns einige Beispiele an. Angenommen, ich habe einen Radiuskreis
5
:Wir können die Fläche und den Umfang des Kreises aus seinem Radius berechnen:
Jetzt möchte ich einen weiteren Radiuskreis erstellen
10
. Ein Weg, dies zu tun, wäre:JavaScript bietet jedoch einen besseren Weg - die Delegierung . Die
Object.create
Funktion wird dazu verwendet:Das ist alles. Sie haben gerade eine prototypische Vererbung in JavaScript durchgeführt. War das nicht einfach? Sie nehmen ein Objekt, klonen es, ändern alles, was Sie brauchen, und hey presto - Sie haben sich ein brandneues Objekt besorgt.
Nun könnten Sie fragen: "Wie ist das einfach? Jedes Mal, wenn ich einen neuen Kreis erstellen möchte, muss ich ihn klonen
circle
und ihm manuell einen Radius zuweisen." Nun, die Lösung besteht darin, eine Funktion zu verwenden, um das schwere Heben für Sie zu erledigen:Tatsächlich können Sie all dies wie folgt zu einem einzigen Objektliteral kombinieren:
Prototypische Vererbung in JavaScript
Wenn Sie im obigen Programm feststellen, dass die
create
Funktion einen Klon von erstelltcircle
, ihm einen neuen zuweistradius
und ihn dann zurückgibt. Genau das macht ein Konstruktor in JavaScript:Das Konstruktormuster in JavaScript ist das invertierte prototypische Muster. Anstatt ein Objekt zu erstellen, erstellen Sie einen Konstruktor. Das
new
Schlüsselwort bindet denthis
Zeiger im Konstruktor an einen Klon desprototype
Konstruktors.Klingt verwirrend? Dies liegt daran, dass das Konstruktormuster in JavaScript die Dinge unnötig kompliziert. Dies ist für die meisten Programmierer schwer zu verstehen.
Anstatt an Objekte zu denken, die von anderen Objekten erben, denken sie an Konstruktoren, die von anderen Konstruktoren erben, und werden dann völlig verwirrt.
Es gibt eine ganze Reihe anderer Gründe, warum das Konstruktormuster in JavaScript vermieden werden sollte. Sie können darüber in meinem Blog-Beitrag hier lesen: Konstruktoren gegen Prototypen
Was sind die Vorteile der prototypischen Vererbung gegenüber der klassischen Vererbung? Lassen Sie uns noch einmal die häufigsten Argumente durchgehen und erklären, warum .
1. Prototypische Vererbung ist einfach
CMS gibt in seiner Antwort an:
Lassen Sie uns überlegen, was wir gerade getan haben. Wir haben ein Objekt
circle
mit einem Radius von erstellt5
. Dann haben wir es geklont und dem Klon einen Radius von gegeben10
.Daher brauchen wir nur zwei Dinge, damit die prototypische Vererbung funktioniert:
Object.create
. B. ).Im Gegensatz dazu ist die klassische Vererbung viel komplizierter. In der klassischen Vererbung haben Sie:
Du hast die Idee. Der Punkt ist, dass die prototypische Vererbung leichter zu verstehen, leichter zu implementieren und leichter zu überlegen ist.
Wie Steve Yegge es in seinem klassischen Blog-Beitrag " Portrait of a N00b " ausdrückt :
Im gleichen Sinne sind Klassen nur Metadaten. Klassen sind für die Vererbung nicht unbedingt erforderlich. Einige Leute (normalerweise n00bs) finden es jedoch angenehmer, mit Klassen zu arbeiten. Es gibt ihnen ein falsches Gefühl der Sicherheit.
Wie ich bereits sagte, geben Klassen den Menschen ein falsches Gefühl der Sicherheit. Zum Beispiel erhalten Sie
NullPointerException
in Java zu viele s, selbst wenn Ihr Code perfekt lesbar ist. Ich finde, dass klassische Vererbung normalerweise die Programmierung behindert, aber vielleicht ist das nur Java. Python hat ein erstaunliches klassisches Vererbungssystem.2. Prototypische Vererbung ist mächtig
Die meisten Programmierer mit klassischem Hintergrund argumentieren, dass die klassische Vererbung leistungsfähiger ist als die prototypische Vererbung, weil sie:
Diese Behauptung ist falsch. Wir wissen bereits, dass JavaScript private Variablen über Schließungen unterstützt , aber was ist mit Mehrfachvererbung? Objekte in JavaScript haben nur einen Prototyp.
Die Wahrheit ist, dass die Vererbung von Prototypen die Vererbung von mehreren Prototypen unterstützt. Prototypische Vererbung bedeutet einfach, dass ein Objekt von einem anderen Objekt erbt. Es gibt tatsächlich zwei Möglichkeiten, die prototypische Vererbung zu implementieren :
Ja, mit JavaScript können Objekte nur an ein anderes Objekt delegiert werden. Sie können jedoch die Eigenschaften einer beliebigen Anzahl von Objekten kopieren. Zum Beispiel
_.extend
macht genau das.Natürlich betrachten viele Programmierer dies nicht als echte Vererbung, weil
instanceof
undisPrototypeOf
sagen etwas anderes. Dies kann jedoch leicht behoben werden, indem auf jedem Objekt, das durch Verkettung von einem Prototyp erbt, eine Reihe von Prototypen gespeichert werden:Daher ist die prototypische Vererbung genauso mächtig wie die klassische Vererbung. Tatsächlich ist es viel leistungsfähiger als die klassische Vererbung, da Sie bei der prototypischen Vererbung von Hand auswählen können, welche Eigenschaften kopiert und welche von verschiedenen Prototypen weggelassen werden sollen.
Bei der klassischen Vererbung ist es unmöglich (oder zumindest sehr schwierig) zu wählen, welche Eigenschaften Sie erben möchten. Sie verwenden virtuelle Basisklassen und Schnittstellen, um das Diamantproblem zu lösen .
In JavaScript werden Sie jedoch höchstwahrscheinlich nie von dem Diamantproblem hören, da Sie genau steuern können, welche Eigenschaften Sie erben möchten und von welchen Prototypen.
3. Prototypische Vererbung ist weniger redundant
Dieser Punkt ist etwas schwieriger zu erklären, da die klassische Vererbung nicht unbedingt zu redundanterem Code führt. Tatsächlich wird die Vererbung, ob klassisch oder prototypisch, verwendet, um die Redundanz im Code zu verringern.
Ein Argument könnte sein, dass die meisten Programmiersprachen mit klassischer Vererbung statisch typisiert sind und der Benutzer explizit Typen deklarieren muss (im Gegensatz zu Haskell, das implizite statische Typisierung aufweist). Dies führt daher zu einem ausführlicheren Code.
Java ist für dieses Verhalten berüchtigt. Ich erinnere mich deutlich daran, dass Bob Nystrom in seinem Blogbeitrag über Pratt Parsers die folgende Anekdote erwähnt hat :
Wieder denke ich, das liegt nur daran, dass Java so viel nervt.
Ein gültiges Argument ist, dass nicht alle Sprachen mit klassischer Vererbung Mehrfachvererbung unterstützen. Wieder fällt mir Java ein. Ja, Java hat Schnittstellen, aber das reicht nicht aus. Manchmal braucht man wirklich Mehrfachvererbung.
Da die prototypische Vererbung eine Mehrfachvererbung ermöglicht, ist Code, der eine Mehrfachvererbung erfordert, weniger redundant, wenn er unter Verwendung einer prototypischen Vererbung geschrieben wird, als in einer Sprache, die eine klassische Vererbung, jedoch keine Mehrfachvererbung aufweist.
4. Die prototypische Vererbung ist dynamisch
Einer der wichtigsten Vorteile der prototypischen Vererbung besteht darin, dass Sie Prototypen nach ihrer Erstellung neue Eigenschaften hinzufügen können. Auf diese Weise können Sie einem Prototyp neue Methoden hinzufügen, die automatisch allen Objekten zur Verfügung gestellt werden, die an diesen Prototyp delegieren.
Dies ist bei der klassischen Vererbung nicht möglich, da Sie eine einmal erstellte Klasse zur Laufzeit nicht mehr ändern können. Dies ist wahrscheinlich der größte Vorteil der prototypischen Vererbung gegenüber der klassischen Vererbung, und er hätte an der Spitze stehen müssen. Ich mag es jedoch, das Beste für das Ende zu speichern.
Fazit
Prototypische Vererbung ist wichtig. Es ist wichtig, JavaScript-Programmierer darüber zu informieren, warum das Konstruktormuster der prototypischen Vererbung zugunsten des prototypischen Musters der prototypischen Vererbung aufgegeben werden soll.
Wir müssen anfangen, JavaScript richtig zu unterrichten, und das bedeutet, neuen Programmierern zu zeigen, wie man Code unter Verwendung des prototypischen Musters anstelle des Konstruktormusters schreibt.
Es wird nicht nur einfacher sein, die Vererbung von Prototypen anhand des prototypischen Musters zu erklären, sondern auch bessere Programmierer.
Wenn Ihnen diese Antwort gefallen hat, sollten Sie auch meinen Blog-Beitrag " Warum prototypische Vererbung wichtig ist " lesen . Vertrauen Sie mir, Sie werden nicht enttäuscht sein.
quelle
Object.create
erstellt ein neues Objekt mit dem angegebenen Prototyp. Ihre Wortwahl erweckt den Eindruck, dass der Prototyp geklont wird.Gestatten Sie mir, die Frage tatsächlich inline zu beantworten.
Die Vererbung von Prototypen hat die folgenden Vorteile:
Es hat jedoch die folgenden Nachteile:
Ich denke, Sie können zwischen den obigen Zeilen lesen und die entsprechenden Vor- und Nachteile traditioneller Klassen- / Objektschemata finden. Es gibt natürlich mehr in jedem Bereich, so dass ich den Rest anderen Personen überlassen werde, die antworten.
quelle
IMO ist der Hauptvorteil der prototypischen Vererbung ihre Einfachheit.
Der prototypische Charakter der Sprache kann klassisch ausgebildete Menschen verwirren , aber es stellt sich heraus, dass dies tatsächlich ein wirklich einfaches und leistungsfähiges Konzept ist, die unterschiedliche Vererbung .
Sie müssen keine Klassifizierung vornehmen , Ihr Code ist kleiner, weniger redundant, Objekte erben von anderen, allgemeineren Objekten.
Wenn Sie prototypisch denken, werden Sie bald feststellen, dass Sie keinen Unterricht benötigen ...
Die prototypische Vererbung wird in naher Zukunft viel beliebter sein. Mit der ECMAScript 5th Edition- Spezifikation wurde die
Object.create
Methode eingeführt, mit der Sie auf wirklich einfache Weise eine neue Objektinstanz erstellen können, die von einer anderen erbt:Diese neue Version des Standards wird von allen Browser-Anbietern implementiert, und ich denke, wir werden anfangen, eine reinere prototypische Vererbung zu sehen ...
quelle
Es gibt wirklich nicht viel zwischen den beiden Methoden zu wählen. Die Grundidee ist, dass die JavaScript-Engine, wenn sie eine Eigenschaft eines zu lesenden Objekts erhält, zuerst die Instanz überprüft und, wenn diese Eigenschaft fehlt, die Prototypkette überprüft. Hier ist ein Beispiel, das den Unterschied zwischen prototypisch und klassisch zeigt:
Prototypisch
Klassisch mit Instanzmethoden (Ineffizient, da jede Instanz ihre eigene Eigenschaft speichert)
Effiziente Klassik
Wie Sie sehen können, hat die Verwendung der prototypischen Vererbung keinen Vorteil, da es möglich ist, den im klassischen Stil deklarierten Prototyp von "Klassen" zu manipulieren. Es ist eine Teilmenge der klassischen Methode.
quelle
Webentwicklung: Prototypische Vererbung vs. klassische Vererbung
http://chamnapchhorn.blogspot.com/2009/05/prototypal-inheritance-vs-classical.html
Klassische Vs prototypische Vererbung - Stapelüberlauf
Klassische Vs prototypische Vererbung
quelle