Im vorherigen Artikel wurde das Konzept des Prototyps eingeführt und die Beziehung zwischen den drei guten Freunden des Konstruktors, dem Prototypobjekt und der Instanz in JavaScript: Jeder Konstruktor hat einen "Guardian" - das Prototyp -Objekt, und es gibt auch eine "Position" des Konstruktors im Herzen des Prototyp -Objekts. Die beiden sind verliebt, aber die Instanz ist "heimlich verliebt" in das Prototypobjekt, und sie hält auch die Position des Prototypobjekts in ihrem Herzen.
JavaScript selbst ist keine objektorientierte Sprache, sondern eine objektbasierte Sprache. Für diejenigen, die an andere OO -Sprachen gewöhnt sind, ist es zunächst etwas unangenehm, weil es hier kein Konzept der "Klasse" gibt oder es keine Unterscheidung zwischen "Klasse" und "Instanz" gibt, geschweige denn den Unterschied zwischen "Elternklasse" und "Unterklasse". Wie werden diese Objekthaufen in JavaScript auf diese Weise verknüpft?
Glücklicherweise lieferte JavaScript zu Beginn seines Entwurfs eine Implementierungsmethode zur "Vererbung". Bevor wir "Vererbung" verstehen, werden wir nun das Konzept der Prototypungsketten verstehen.
Prototypkette
Wir wissen, dass Prototypen einen Zeiger auf den Konstruktor haben. Was ist, wenn wir das Subklass -Prototyp -Objekt gleich einer anderen Instanz der neuen Superklasse () machen? Zu diesem Zeitpunkt enthält das Subcass -Prototyp -Objekt einen Zeiger auf den Superklassenprototyp, und der Superklasseprototyp enthält auch einen Zeiger auf den Superclass -Konstruktor. . . Auf diese Weise wird eine Prototypkette gebildet.
Der spezifische Code lautet wie folgt:
Funktion superClass () {this.name = "women"} superClass.prototype.saywhat = function () {return this.name + ": i'ma girl!"; } function subclass () {this.subname = "Ihre Schwester"; } Subclass.Prototype = new SuperClass (); Subclass.prototype.subsaywhat = function () {return this.subname + ": i'ma schönes Mädchen"; } var sub = new subClass (); console.log (sub.saywhat ()); // Frauen: I'ma Mädchen!Verwenden Sie die Prototypkette, um die Vererbung zu erreichen
Aus dem obigen Code können wir sehen, dass die Unterklasse die Eigenschaften und Methoden der Superklasse erbt. Diese vererbte Implementierung erfolgt durch die Zuweisung der Instanz der Superklasse dem Prototyp -Objekt der Unterklasse. Auf diese Weise wird das Prototypobjekt der Unterklasse durch eine Instanz der Superklasse überschrieben, die alle Eigenschaften und Methoden mit einem Zeiger auf das Prototyp -Objekt der Superklasse verfügt.
Es gibt einige Dinge, die bei der Implementierung der Vererbung mit Prototypketten geachtet werden müssen:
Achten Sie auf die Änderungen des Konstruktors nach der Vererbung. Hier der Konstruktor der Subpunkte auf die Superklasse, weil der Prototyp der Unterklasse auf die Superklasse zeigt. Wenn Sie die Prototypkette verstehen, ignorieren Sie das Standardobjektobjekt am Ende nicht, weshalb wir integrierte Methoden wie das ToString in allen Objekten verwenden können.
Bei der Implementierung der Vererbung durch die Prototyp -Kette können Sie keine wörtliche Definition der Prototyp -Methode verwenden, da dies das Prototyp -Objekt umschreibt (ebenfalls im vorherigen Artikel eingeführt):
Funktion superClass () {this.name = "women"} superClass.prototype.saywhat = function () {return this.name + ": i'ma girl!"; } function subclass () {this.subname = "Ihre Schwester"; } Subclass.Prototype = new SuperClass (); Subclass.prototype = {// Das Prototyp -Objekt wird hier überschrieben, weil die Superklassen -Attribute und -Methoden nicht vererbt werden können Subsaywhat: function () {return this.subname + ": i'ma Schönes Mädchen"; }} var sub = new subclass (); console.log (sub.saywhat ()); // typeerror: undefined ist keine FunktionEin Problem mit der Instanzfreigabe. Bei der früheren Erläuterung des Prototyps und des Konstruktors haben wir einmal eingeführt, dass Prototypen, die Referenztypattribute enthalten, von allen Fällen gemeinsam genutzt werden. In ähnlicher Weise wird auch die Eigenschaften des Referenztyps im Prototyp "Elternklasse" im Prototyp geteilt. Wenn wir die Referenztypattribute der "Elternklasse" durch den Prototyp -Vererbung ändern, werden alle anderen vom Prototyp geerbten Instanzen betroffen. Dies verschwendet nicht nur Ressourcen, sondern auch ein Phänomen, das wir nicht sehen wollen:
Funktion SuperClass () {this.name = "Frauen"; this.bra = ["a", "b"]; } function subclass () {this.subname = "Ihre Schwester"; } Subclass.Prototype = new SuperClass (); var sub1 = neuer subclass (); sub1.name = "Mann"; sub1.bra.push ("c"); console.log (sub1.name); // Man console.log (sub1.bra); // ["a", "b", "c"] var sub2 = new subclass (); console.log (sub1.name); // woman console.log (sub2.bra); // ["a", "b", "c"]Hinweis: Fügen Sie dem Array hier ein Element hinzu. Alle von der Superclass geerbten Instanzen sind beeinflusst. Wenn Sie das Attribut des Namens jedoch ändern, wirkt es sich jedoch nicht auf andere Instanzen aus, da das Array ein Referenztyp ist und der Name ein primitiver Typ ist.
Wie löst ich das Problem der Instanzfreigabe? Lass uns weiter nach unten schauen ...
Klassische Vererbung (Konstruktor Diebstahl)
Da wir vorgestellt haben, dass wir Prototypen nur selten verwenden, um Objekte allein in der tatsächlichen Entwicklung zu definieren, verwenden wir selten Prototypketten allein. Um das Problem der Freigabe von Referenztypen zu lösen, haben JavaScript -Entwickler das klassische Erbschaftsmuster eingeführt (einige Menschen nennen den geliehenen Konstruktor -Erbschaft). Die Implementierung ist sehr einfach, Supertyp -Konstruktoren in Subtypkonstruktoren aufzurufen. Wir müssen die von JavaScript bereitgestellte CALL () oder apply () -Funktion verwenden. Schauen wir uns das Beispiel an:
Funktion SuperClass () {this.name = "Frauen"; this.bra = ["a", "b"];} Funktion subclass () {this.subname = "Ihre Schwester"; // dem aktuellen Konstruktor den Umfang der Superklasse zuweisen, um die Vererbung von SuperClass.call (this) zu implementieren;} var sub1 = new subclass (); sub1.bra.push ("c"); console.log (sub1.bra); // ["a", "b", "c" var sub2 = new = new = neu Subclass (); console.log (sub2.bra); // ["a", "b"]SuperClass.call (this); Dieser Satz bedeutet, dass die Initialisierungsarbeit des Superklasse -Konstruktors in der Instanzumgebung (Kontext) der Unterklasse aufgerufen wird, so dass jede Instanz eine eigene Kopie des BRA -Attributs hat, was sich nicht aufeinander auswirkt.
Diese Implementierungsmethode ist jedoch immer noch nicht perfekt. Da der Konstruktor eingeführt wird, stehen wir auch dem Problem mit dem im vorherigen Artikel erwähnten Konstruktor vor: Wenn im Konstruktor eine Methodendefinition vorhanden ist, gibt es eine separate Funktionsreferenz für keine der Instanzen. Unser Ziel ist es, diese Methode zu teilen, und die Methoden, die wir im Supertyp -Prototyp definieren, können in der Subtyp -Instanz nicht aufgerufen werden:
Funktion SuperClass () {this.name = "Frauen"; this.bra = ["a", "b"]; } Superclass.prototype.saywhat = function () {console.log ("hello"); } function subclass () {this.subname = "Ihre Schwester"; SuperClass.call (this); } var sub1 = new subclass (); console.log (sub1.saywhat ()); // typeerror: undefined ist keine FunktionWenn Sie den vorherigen Artikel über Prototypobjekte und Konstrukteure gelesen haben, müssen Sie bereits die Antwort auf die Lösung dieses Problems kennen, dh der Routine des vorherigen Artikels und verwenden Sie "Kombinations -Punch"!
Kombinationsvererbung
Die Kombinationsvererbung ist eine Möglichkeit, die Vorteile der Prototypkette und des Konstruktors zu kombinieren und sie zu kombinieren, um die Vererbung zu erreichen. Einfach ausgedrückt wird die Prototyp -Kette verwendet, um Attribute und Methoden zu erben und geliehene Konstrukteure zu verwenden, um die Vererbung von Instanzattributen zu implementieren. Dies löst nicht nur das Problem der Instanzattributfreigabe, sondern ermöglicht auch, dass Super-Typ-Attribute und -methoden vererbt werden:
Funktion SuperClass () {this.name = "Frauen"; this.bra = ["a", "b"]; } Superclass.prototype.saywhat = function () {console.log ("hello"); } function subclass () {this.subname = "Ihre Schwester"; SuperClass.call (this); // Der zweite Anruf bei SuperClass} subclass.Prototype = new SuperClass (); // Der erste Anruf bei Superclass var sub1 = new subclass (); console.log (sub1.saywhat ()); //HalloDie Kombinationsvererbungsmethode ist auch die am häufigsten verwendete Methode zur Implementierung der Vererbung in der tatsächlichen Entwicklung. Zu diesem Zeitpunkt kann es Ihren tatsächlichen Entwicklungsbedürfnissen erfüllen, aber das Streben der Menschen nach Perfektion ist endlos, sodass es zwangsläufig jemanden "finden" über dieses Muster: Ihr Muster hat den Super-Typ-Konstruktor zweimal bezeichnet! Zweimal. . . Hast du es geschafft? Ist diese Verstärkung des 100 -fachen des Leistungsverlusts?
Die leistungsstärkste Widerlegung ist es, eine Lösung zu finden, aber zum Glück hat der Entwickler die beste Lösung für dieses Problem gefunden:
Parasitäre Kombinationserbranz
Bevor wir diese Vererbungsmethode einführen, verstehen wir zunächst das Konzept des parasitären Konstruktors. Der parasitäre Konstruktor ähnelt dem oben erwähnten Werksmuster. Seine Idee ist es, eine gemeinsame Funktion zu definieren. Diese Funktion wird speziell verwendet, um die Erstellung eines Objekts zu verarbeiten. Nach Abschluss der Erstellung gibt es dieses Objekt zurück. Diese Funktion ist einem Konstruktor sehr ähnlich, aber der Konstruktor gibt keinen Wert zurück:
Funktion GF (Name, Bra) {var obj = new Object (); obj.name = name; obj.bra = bra; obj.saywhat = function () {console.log (this.name); } return obj;} var gf1 = new gf ("bingbing", "c ++"); console.log (gf1.saywhat ()); // BingbingDie Umsetzung der parasitären Vererbung ähnelt dem parasitären Konstruktor. Es erstellt eine "Werks" -Funktion, die nicht von bestimmten Typen abhängt, sich speziell mit dem Objekt -Erbschaftsprozess befasst, und gibt dann die ererbte Objektinstanz zurück. Glücklicherweise erfordert wir nicht, dass wir es selbst umsetzen. DAO GE (Douglas) hat uns seit langem eine Implementierungsmethode zur Verfügung gestellt:
Funktionsobjekt (obj) {Funktion f () {} f.prototype = obj; Neue f ();} var superklasse = {name: "bingbing", bra: "c ++"} var subclass = Objekt (SuperClass); console.log (subclass.name); // BingbingEin einfacher Konstruktor wird in einer öffentlichen Funktion bereitgestellt, und dann ist eine Instanz des in das in das Prototypenobjekts des Konstruktors übergebenen Objekts zugewiesen, und die Rückgabe einer Instanz des Konstruktors ist sehr einfach, aber die Wirksamkeit ist sehr gut, nicht wahr? Diese Methode wird später als "Prototyp -Vererbung" bezeichnet, und die parasitäre Vererbung wird basierend auf dem Prototyp erreicht, indem die benutzerdefinierten Eigenschaften des Objekts verstärkt werden:
Funktion BuildObj (obj) {var o = Object (obj); o.saywhat = function () {console.log ("Hallo"); } return o;} var superklasse = {name: "bingbing", bra: "c ++"} var gf = BuildObj (SuperClass); gf.saywhat (); // HalloDie parasitäre Vererbung sieht sich auch dem Problem der Funktion der Funktion in Prototypen aus, sodass die Menschen wieder Bausteine zusammenstellen, und die parasitäre Kombinationsvererbung wurde geboren, um das Problem des Aufrufens des übergeordneten Konstruktors bei der Angabe eines Subtyp -Prototyps und gleichzeitig zu lösen, um die Wiederverbrauch der Funktion der Funktion zu maximieren. Basierend auf den obigen grundlegenden Implementierungsmethoden lauten wie folgt:
// Die Parameter sind zwei Konstruktorenfunktionen inheritObj (sub, sup) {// Instanz -Vererbung implementieren und eine Kopie des Supertype var proto = -objekts (sup.Prototype) erhalten; // respektieren Sie das Konstruktorattribut des Proto -Instanz -Proto.Constructor = subs; // dem Prototyp des Subtyps sub.prototype = proto;} function SuperClass () {this.name = "Frauen" dem Prototyp zuweisen. this.bra = ["a", "b"];} superklasse.prototype.saywhat = function () {console.log ("hello");} function subclass () {this.name = "women"; this.bra = ["a", "b"];} SuperClass.Prototype.saywhat = function () {console.log ("Hallo");} Funktion subclass () {this.subname = "Ihre Schwester"; Superklasse.call (this);} inheritObj (subclass, SuperClass); var sub1 = new subclass (); console.log (sub1.saywhat ()); //HalloDiese Implementierung vermeidet zwei Aufrufe bei Supertypen und spart unnötige Eigenschaften für Unterklassen. Zu diesem Zeitpunkt ist die Erbschaftsreise wirklich vorbei, und diese Implementierung ist auch zur idealsten Vererbungs -Implementierungsmethode geworden! Die Kontroverse der Menschen über die Erbe von JavaScript geht weiter. Einige befürworten OO, und einige lehnen es ab, unnötige Anstrengungen in JavaScript zu unternehmen, um die Merkmale von OO zu verwirklichen. Was ist, wenn es so ist, zumindest habe ich ein tieferes Verständnis!