Vorteile der prototypischen Vererbung gegenüber der klassischen?

271

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.

Pierreten
quelle

Antworten:

560

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):

  1. Es ist einfach.
  2. Es ist mächtig.
  3. Dies führt zu kleinerem, weniger redundantem Code.
  4. Es ist dynamisch und daher besser für dynamische Sprachen.

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:

  1. Das prototypische Muster der prototypischen Vererbung.
  2. Das Konstruktormuster 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):

Und wir haben es als kleiner Bruder von Java vorangetrieben, da eine ergänzende Sprache wie Visual Basic zu dieser Zeit in den Sprachfamilien von Microsoft zu C ++ gehörte.

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:

Diese Indirektion sollte die Sprache klassisch ausgebildeten Programmierern vertrauter erscheinen lassen, hat dies jedoch nicht getan, wie aus der sehr geringen Meinung der Java-Programmierer zu JavaScript hervorgeht. Das Konstruktormuster von JavaScript hat die klassische Masse nicht angesprochen. Es verdeckte auch die wahre prototypische Natur von JavaScript. Infolgedessen gibt es nur sehr wenige Programmierer, die wissen, wie man die Sprache effektiv einsetzt.

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:

  1. Erstellen Sie ein brandneues Objekt.
  2. Klonen Sie ein vorhandenes Objekt und erweitern Sie es.

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:

var circle = {
    radius: 5
};

Wir können die Fläche und den Umfang des Kreises aus seinem Radius berechnen:

circle.area = function () {
    var radius = this.radius;
    return Math.PI * radius * radius;
};

circle.circumference = function () {
    return 2 * Math.PI * this.radius;
};

Jetzt möchte ich einen weiteren Radiuskreis erstellen 10. Ein Weg, dies zu tun, wäre:

var circle2 = {
    radius: 10,
    area: circle.area,
    circumference: circle.circumference
};

JavaScript bietet jedoch einen besseren Weg - die Delegierung . Die Object.createFunktion wird dazu verwendet:

var circle2 = Object.create(circle);
circle2.radius = 10;

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 circleund ihm manuell einen Radius zuweisen." Nun, die Lösung besteht darin, eine Funktion zu verwenden, um das schwere Heben für Sie zu erledigen:

function createCircle(radius) {
    var newCircle = Object.create(circle);
    newCircle.radius = radius;
    return newCircle;
}

var circle2 = createCircle(10);

Tatsächlich können Sie all dies wie folgt zu einem einzigen Objektliteral kombinieren:

var circle = {
    radius: 5,
    create: function (radius) {
        var circle = Object.create(this);
        circle.radius = radius;
        return circle;
    },
    area: function () {
        var radius = this.radius;
        return Math.PI * radius * radius;
    },
    circumference: function () {
        return 2 * Math.PI * this.radius;
    }
};

var circle2 = circle.create(10);

Prototypische Vererbung in JavaScript

Wenn Sie im obigen Programm feststellen, dass die createFunktion einen Klon von erstellt circle, ihm einen neuen zuweist radiusund ihn dann zurückgibt. Genau das macht ein Konstruktor in JavaScript:

function Circle(radius) {
    this.radius = radius;
}

Circle.prototype.area = function () {
    var radius = this.radius;
    return Math.PI * radius * radius;
};

Circle.prototype.circumference = function () {         
    return 2 * Math.PI * this.radius;
};

var circle = new Circle(5);
var circle2 = new Circle(10);

Das Konstruktormuster in JavaScript ist das invertierte prototypische Muster. Anstatt ein Objekt zu erstellen, erstellen Sie einen Konstruktor. Das newSchlüsselwort bindet den thisZeiger im Konstruktor an einen Klon des prototypeKonstruktors.

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:

Meiner Meinung nach ist der Hauptvorteil der prototypischen Vererbung ihre Einfachheit.

Lassen Sie uns überlegen, was wir gerade getan haben. Wir haben ein Objekt circlemit einem Radius von erstellt 5. Dann haben wir es geklont und dem Klon einen Radius von gegeben 10.

Daher brauchen wir nur zwei Dinge, damit die prototypische Vererbung funktioniert:

  1. Eine Möglichkeit, ein neues Objekt zu erstellen (z. B. Objektliterale).
  2. Eine Möglichkeit, ein vorhandenes Objekt zu erweitern (z Object.create. B. ).

Im Gegensatz dazu ist die klassische Vererbung viel komplizierter. In der klassischen Vererbung haben Sie:

  1. Klassen.
  2. Objekt.
  3. Schnittstellen.
  4. Abstrakte Klassen.
  5. Abschlussklassen.
  6. Virtuelle Basisklassen.
  7. Konstruktoren.
  8. Zerstörer.

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 :

Metadaten sind jede Art von Beschreibung oder Modell von etwas anderem. Die Kommentare in Ihrem Code sind nur eine Beschreibung der Berechnung in natürlicher Sprache. Was Metadaten-Metadaten ausmacht, ist, dass dies nicht unbedingt erforderlich ist. Wenn ich einen Hund mit Stammbaumpapieren habe und den Papierkram verliere, habe ich immer noch einen vollkommen gültigen Hund.

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.

Wir wissen auch, dass statische Typen nur Metadaten sind. Sie sind eine spezielle Art von Kommentar, der sich an zwei Arten von Lesern richtet: Programmierer und Compiler. Statische Typen erzählen eine Geschichte über die Berechnung, vermutlich um beiden Lesergruppen zu helfen, die Absicht des Programms zu verstehen. Die statischen Typen können jedoch zur Laufzeit weggeworfen werden, da es sich letztendlich nur um stilisierte Kommentare handelt. Sie sind wie Stammbaumpapiere: Es könnte einen bestimmten unsicheren Persönlichkeitstyp über ihren Hund glücklicher machen, aber dem Hund ist das sicher egal.

Wie ich bereits sagte, geben Klassen den Menschen ein falsches Gefühl der Sicherheit. Zum Beispiel erhalten Sie NullPointerExceptionin 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:

  1. Private Variablen.
  2. Mehrfachvererbung.

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 :

  1. Delegation oder differenzielle Vererbung
  2. Klonen oder verkettete Vererbung

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 _.extendmacht genau das.

Natürlich betrachten viele Programmierer dies nicht als echte Vererbung, weil instanceofund isPrototypeOfsagen 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:

function copyOf(object, prototype) {
    var prototypes = object.prototypes;
    var prototypeOf = Object.isPrototypeOf;
    return prototypes.indexOf(prototype) >= 0 ||
        prototypes.some(prototypeOf, prototype);
}

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 :

Sie müssen Javas Bürokratie "Bitte unterschreiben Sie es in vierfacher Ausfertigung" hier lieben.

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.

Aadit M Shah
quelle
33
Obwohl ich verstehe, woher Sie kommen, und ich stimme zu, dass die prototypische Vererbung sehr nützlich ist, denke ich, dass Sie bereits zum Scheitern verurteilt sind, wenn Sie davon ausgehen, dass die prototypische Vererbung besser ist als die klassische Vererbung. Meine Bibliothek jTypes ist eine klassische Vererbungsbibliothek für JavaScript. Als Typ, der sich die Zeit dafür genommen hat, werde ich immer noch hier sitzen und sagen, dass die Vererbung von Prototypen fantastisch und sehr nützlich ist. Aber es ist einfach nur ein Werkzeug unter vielen, das ein Programmierer hat. Die prototypische Vererbung hat immer noch viele Nachteile.
Redline
7
Ich stimme voll und ganz dem zu, was Sie gesagt haben. Ich habe das Gefühl, dass zu viele Programmierer JavaScript wegen fehlender klassischer Vererbung ablehnen oder es als einfache und dumme Sprache anprangern. Es ist tatsächlich ein äußerst leistungsfähiges Konzept, da stimme ich zu, und viele Programmierer sollten es akzeptieren und lernen. Abgesehen davon habe ich auch das Gefühl, dass es eine beträchtliche Anzahl von Entwicklern in JavaScript gibt, die sich gegen jede Form der klassischen Vererbung aussprechen, wenn sie überhaupt keine Grundlage für ihre Argumente haben. Beide sind für sich genommen gleich mächtig und ebenso nützlich.
Redline
9
Nun, das ist Ihre Meinung, aber ich werde weiterhin anderer Meinung sein, und ich denke, die wachsende Beliebtheit von Dingen wie CoffeeScript und TypeScript zeigt, dass es eine große Community von Entwicklern gibt, die diese Funktionalität gegebenenfalls nutzen möchten. Wie Sie sagten, fügt ES6 syntaktischen Zucker hinzu, bietet jedoch immer noch nicht die Erweiterbarkeit von jTypes. Nebenbei bemerkt, ich bin nicht derjenige, der für Ihre Ablehnung verantwortlich ist. Obwohl ich mit Ihnen nicht einverstanden bin, habe ich nicht das Gefühl, dass Sie eine schlechte Antwort haben. Sie waren sehr gründlich.
Redline
25
Sie verwenden häufig Wortklone , was einfach falsch ist. Object.createerstellt ein neues Objekt mit dem angegebenen Prototyp. Ihre Wortwahl erweckt den Eindruck, dass der Prototyp geklont wird.
Pavel Horal
7
@Aadit: Es ist wirklich nicht nötig, so defensiv zu sein. Ihre Antwort ist sehr detailliert und verdient Stimmen. Ich habe nicht vorgeschlagen, dass "verknüpft" ein Ersatz für "Klon" sein sollte, sondern dass es die Verbindung zwischen einem Objekt und dem Prototyp, von dem es erbt, angemessener beschreibt, unabhängig davon, ob Sie Ihre eigene Definition des Begriffs "Klon" behaupten " oder nicht. Ändern Sie es oder ändern Sie es nicht, es liegt ganz bei Ihnen.
Andy E
42

Gestatten Sie mir, die Frage tatsächlich inline zu beantworten.

Die Vererbung von Prototypen hat die folgenden Vorteile:

  1. Es eignet sich besser für dynamische Sprachen, da die Vererbung genauso dynamisch ist wie die Umgebung, in der sie sich befindet. (Die Anwendbarkeit auf JavaScript sollte hier offensichtlich sein.) Auf diese Weise können Sie schnell Dinge wie das Anpassen von Klassen ohne große Mengen an Infrastrukturcode erledigen .
  2. Es ist einfacher, ein Prototyping-Objektschema zu implementieren als die klassischen Klassen / Objekt-Dichotomie-Schemata.
  3. Die komplexen scharfen Kanten um das Objektmodell wie "Metaklassen" (ich habe nie eine Metaklasse, die mir gefallen hat ... sorry!) Oder "Eigenwerte" oder ähnliches sind nicht mehr erforderlich.

Es hat jedoch die folgenden Nachteile:

  1. Die Typprüfung einer Prototypsprache ist nicht unmöglich, aber sehr, sehr schwierig. Die meisten "Typprüfungen" prototypischer Sprachen sind reine "Duck Typing" -Stilprüfungen zur Laufzeit. Dies ist nicht für alle Umgebungen geeignet.
  2. Ähnlich schwierig ist es, beispielsweise den Methodenversand durch statische (oder oft sogar dynamische!) Analyse zu optimieren. Es kann (ich betone: kann ) sehr leicht sehr ineffizient sein.
  3. In ähnlicher Weise kann (und ist) die Objekterstellung in einer Prototyping-Sprache viel langsamer sein als in einem konventionelleren Dichotomieschema zwischen Klasse und Objekt.

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.

NUR MEINE RICHTIGE MEINUNG
quelle
1
Hey schau, eine prägnante Antwort, die kein Fanboy ist. Ich wünschte wirklich, dies wäre die beste Antwort auf die Frage.
Siliconrockstar
Wir haben heute dynamische Just-in-Time-Compiler, die den Code kompilieren können, während der Code ausgeführt wird, und für jeden Abschnitt unterschiedliche Codeteile erstellen. JavaScript ist tatsächlich schneller als Ruby oder Python, die aus diesem Grund klassische Klassen verwenden, selbst wenn Sie Prototypen verwenden, da viel Arbeit an der Optimierung geleistet wurde.
aoeu256
28

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.createMethode eingeführt, mit der Sie auf wirklich einfache Weise eine neue Objektinstanz erstellen können, die von einer anderen erbt:

var obj = Object.create(baseInstance);

Diese neue Version des Standards wird von allen Browser-Anbietern implementiert, und ich denke, wir werden anfangen, eine reinere prototypische Vererbung zu sehen ...

CMS
quelle
11
"Ihr Code ist kleiner, weniger redundant ...", warum? Ich habe mir den Wikipedia-Link für "Differentialvererbung" angesehen und es gibt nichts, was diese Behauptungen stützt. Warum würde klassische Vererbung zu größerem, redundanterem Code führen?
Noel Abrahams
4
Genau, ich stimme Noel zu. Prototypische Vererbung ist einfach eine Möglichkeit, einen Job zu erledigen, aber das macht es nicht richtig. Verschiedene Werkzeuge werden für verschiedene Jobs auf unterschiedliche Weise ausgeführt. Prototypische Vererbung hat ihren Platz. Es ist ein äußerst leistungsfähiges und einfaches Konzept. Angesichts des Mangels an Unterstützung für echte Kapselung und Polymorphismus ist JavaScript jedoch erheblich benachteiligt. Diese Methoden gibt es schon viel länger als JavaScript und sie sind in ihren Prinzipien solide. Prototypisch zu denken ist "besser", also ist es einfach die falsche Mentalität.
Redline
1
Sie können die klassenbasierte Vererbung mithilfe der prototypbasierten Vererbung simulieren, nicht jedoch umgekehrt. Das könnte ein gutes Argument sein. Außerdem sehe ich die Kapselung eher als Konvention als als Sprachfunktion (normalerweise können Sie die Kapselung durch Reflexion unterbrechen). In Bezug auf Polymorphismus - alles, was Sie gewinnen, ist, dass Sie beim Überprüfen von Methodenargumenten keine einfachen "Wenn" -Bedingungen schreiben müssen (und ein wenig Geschwindigkeit, wenn die Zielmethode während der Kompilierung aufgelöst wird). Keine wirklichen JavaScript-Nachteile hier.
Pavel Horal
Prototypen sind großartig, IMO. Ich denke darüber nach, eine funktionale Sprache wie Haskell zu erstellen ... aber anstatt Abstraktionen zu erstellen, werde ich alles auf Prototypen basieren. Anstatt die Summe zu verallgemeinern und faktoriell zu "falten", sollten Sie den Prototyp der Summenfunktion verwenden und das + durch * und 0 durch 1 ersetzen, um das Produkt herzustellen. Ich werde "Monaden" als Prototypen erklären, die "dann" durch Versprechen / Rückrufe ersetzen, wobei flatMap ein Synonym für "dann" ist. Ich denke, Prototypen können helfen, funktionale Programmierung in die Massen zu bringen.
aoeu256
11

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

var single = { status: "Single" },
    princeWilliam = Object.create(single),
    cliffRichard = Object.create(single);

console.log(Object.keys(princeWilliam).length); // 0
console.log(Object.keys(cliffRichard).length); // 0

// Marriage event occurs
princeWilliam.status = "Married";

console.log(Object.keys(princeWilliam).length); // 1 (New instance property)
console.log(Object.keys(cliffRichard).length); // 0 (Still refers to prototype)

Klassisch mit Instanzmethoden (Ineffizient, da jede Instanz ihre eigene Eigenschaft speichert)

function Single() {
    this.status = "Single";
}

var princeWilliam = new Single(),
    cliffRichard = new Single();

console.log(Object.keys(princeWilliam).length); // 1
console.log(Object.keys(cliffRichard).length); // 1

Effiziente Klassik

function Single() {
}

Single.prototype.status = "Single";

var princeWilliam = new Single(),
    cliffRichard = new Single();

princeWilliam.status = "Married";

console.log(Object.keys(princeWilliam).length); // 1
console.log(Object.keys(cliffRichard).length); // 0
console.log(cliffRichard.status); // "Single"

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.

Noel Abrahams
quelle
2
Wenn Sie sich andere Antworten und Ressourcen zu diesem Thema ansehen, scheint Ihre Antwort zu lauten: "Prototypische Vererbung ist eine Teilmenge des syntaktischen Zuckers, der JavaScript hinzugefügt wurde, um das Auftreten klassischer Vererbung zu ermöglichen." Das OP scheint nach den Vorteilen der prototypischen Vererbung in JS gegenüber der klassischen Vererbung in anderen Sprachen zu fragen, anstatt Instanziierungstechniken in JavaScript zu vergleichen.
Ein Fader Darkly
2

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

schäbig
quelle
20
Ich denke, es ist besser, den Inhalt von Links zusammenzufassen, als den Link einzufügen (was ich selbst getan habe), es sei denn, es ist ein anderer SO-Link. Dies liegt daran, dass Links / Websites ausfallen und Sie die Antwort auf die Frage verlieren. Dies wirkt sich möglicherweise auf die Suchergebnisse aus.
James Westgate
Der erste Link beantwortet nicht die Frage, warum prototypische Vererbung? Es beschreibt es einfach.
Viebel