Um den Prototyp in JS zu verstehen, müssen Sie zunächst die folgenden Konzepte verstehen
1. Alles in JS ist ein Objekt
2. Alles in JS wird aus dem Objekt abgeleitet, dh der Endpunkt der Prototypkette aller Dinge auf Objekt zeigt.
// ["constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", // "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__", // "__lookupSetter__"] console.log (Object.getownPropertynames (Object.Prototype));
3. Die subtile Beziehung zwischen Konstruktoren und Instanzen (Objekten) in JS
Die Konstruktoren definieren Prototypen, um sich über die Spezifikationen ihrer Instanzen zu einigen und dann Instanzen durch neue zu konstruieren. Ihre Funktion ist es, Objekte zu erzeugen.
Der Konstruktor (Methode) selbst ist eine Instanz der Methode (Funktion), daher kann es auch für sein __Proto __ (Protochain) gefunden werden.
Objekt / Funktion f () {} Dies ist der Konstruktor, einer wird von der JS Native API bereitgestellt und der andere wird angepasst
New Object () / New F () ist eine Instanz
Die Beispiele können nur "nur" angesehen werden, um herauszufinden, auf welchem Prototyp er basiert.
Der Prototyp, der die Instanz "nicht" nicht definiert, und täuscht sich dann, um eine Instanz der Instanz zu erstellen.
Üben Sie, um wahres Wissen zu erzeugen, und nur durch Beobachten/Denken Sie sich selbst können Sie wirklich verstehen:
// Schauen wir uns zunächst an, was der Konstruktor ist // Funktion leer () {} Funktion leer () {} console.log (Funktion.Prototyp, Funktion .__ proto__); // Objekt {} Funktion leer () {} console.log (Object.Prototype, Object .__ proto__); Funktion f () {} // f {} Funktion leer () {} console.log (f.prototype, f .__ proto__);Sie mögen schwindelig sein, lass es uns aufschlüsseln.
Prototyp
Das Format des Prototypausgangs lautet: Konstruktor -Name -Prototyp
Schauen wir uns zunächst an, welches Object.Prototyp -Ausgänge ausgibt?
Objekt {} -> Das vorherige Objekt ist der Name des Konstruktors, und der nächste repräsentiert den Prototyp. Hier ist ein {}, dh eine Instanz eines Objektobjekts (leeres Objekt)
Dann verstehen wir, was es bedeutet. F ist der Name des Konstruktors, und der Prototyp ist auch ein leeres Objekt
// Schauen wir uns das Beispiel an, das vom Konstruktor var o = new Object () erstellt wurde. // var o = {}; // Undefined Object {} console.log (O.Prototype, o .__ proto__); Funktion f () {} var i = new f (); // undefined f {} console.log (i.prototype, i .__ proto__);Lassen Sie uns etwas tiefer gehen und den Prototyp von F definieren, um zu sehen, was passieren wird?
Funktion f () {} f.prototype.a = function () {}; var i = neu f (); // undefined f {a: function} console.log (i.prototype, i .__ proto__);Auf diese Weise können wir deutlich erkennen, dass ich aus F konstruiert ist. Der Prototyp ist {A: Funktion}, was bedeutet, dass eine Methode A zum ursprünglichen leeren Objektprototyp hinzugefügt wurde.
Lassen Sie uns die Situation ändern. Was wird passieren, wenn der Prototyp, der F vollständig abdeckt?
Funktion f () {} f.prototype = {a: function () {}}; var i = neu f (); // Undefined Object {a: function} console.log (i.prototype, i .__ proto__);Hey ~ Warum deutet es hier an, dass ich aus dem Objekt konstruiert bin? NEIN!
Da wir den Prototyp von F vollständig überschreiben, geben wir den Prototyp als Objekt {A: Funktion} an. Dies führt jedoch dazu, dass die ursprünglichen Konstruktorinformationen verloren gehen und der vom Objekt {A: Funktion} angegebene Konstruktor werden.
Was ist der Konstruktor des Objekts {a: function}?
Weil das Objekt {a: function} tatsächlich relativ zu ist zu
var o = {a: function () {}} // neues ObjektDann ist der Konstruktor von O natürlich ein Objekt
Korrigieren wir diesen Fehler
Funktion f () {} f.prototype = {a: function () {}} // Spezifizieren Sie den richtigen Konstruktor F.Prototype.Constructor = f; var i = neu f (); // undefined f {a: Funktion, Konstruktor: Funktion} console.log (i.prototype, i .__ proto__);Jetzt können Sie die richtigen Prototypinformationen erneut erhalten ~
Prototypkette
Schauen wir uns dann an, welche Prototyp -Kette ist?
Einfach ausgedrückt ist es dasselbe wie die Vererbungsbeziehung (Kette) in OOP. Schauen Sie Schicht für Schicht, bis das endgültige Objekt.Prototype
Das Wichtigste ist, herauszufinden, welche Dinge in JS (Instanzen) Objekte sind. Das ist einfach, alles in JS ist Objekte!
Dann müssen wir herausfinden, dass ein Objekt einen Prototyp hat!
Dann beweisen wir es:
Objekt // Dies ist eine Funktion, die Funktion ist ein Instanzobjekt der Funktion, daher ist es das Objekt .__ proto__ == -Funktion.Prototyp // Dann der Prototyp des Objekts, true // Dies ist ein gewöhnliches Objekt Object.Prototype .__ proto__ == null // true function // Dies ist auch eine Funktion, ja! Funktion .__ proto__ == Funktion.Prototype // True Funktion a () {} // Dies ist eine benutzerdefinierte Funktion, und es ist immer noch eine Funktion, die richtig ist! A .__ proto__ == function var a = new a () a .__ proto__ == a.prototype // Instanz A wird vom A -Konstruktor konstruiertPrototyp und __Proto__
Jedes Objekt enthält ein __Proto__, das auf den "Prototyp" des Objekts hinweist.
Ähnliches ist, dass jede Funktion einen Prototyp enthält. Wofür ist dieses Prototypobjekt?
Schauen wir uns den folgenden Code an, wobei der Konstruktor zum Erstellen eines Objekts verwendet wird (das obige soll ein Objekt in Form einer wörtlichen Form erstellen).
Funktion foo () {}; var foo = new foo (); console.log (foo .__ proto__);Stellen Sie sich vor, worauf wird der __Proto__ dieses Foo -Objekts hinweisen?
Ein Objekt, das das Konstruktorattribut enthält? Es spielt keine Rolle, ob Sie es nicht sehr verstehen. Drucken Sie das Prototyp -Attribut der Funktion foo aus und vergleichen Sie es mit Ihnen zu wissen.
Funktion foo () {}; var foo = new foo (); console.log (foo .__ proto __); console.log (foo.prototype); console.log (foo .__ proto__ === Foo.Prototype);Es stellt sich heraus, dass das __Proto__ des Objekts foo, das aus Neuen kommt, nur auf den Prototyp der Funktion foo hinweist.
foo .__ proto__ -> foo.prototype
Was bringt es, JS wie dieses zu entwerfen? Wenn man sich an das erinnert, was oben in der Welt von JS erwähnt wurde, werden Objekte nicht basierend auf Klassen (Formen) erstellt, sondern aus Prototypen (ein anderes Objekt) abgeleitet.
Wenn wir neue Operationen ausführen, um ein neues Objekt zu erstellen, werden wir uns nicht in die spezifische Implementierung neuer Vorgänge einlassen, aber wir sind uns sicher - das heißt, wir verweisen auf ein Prototyp -Objekt für das neue Objekt __Proto__.
Nur dieser Code
Funktion foo () {}; var foo = new foo ();Wer zeigt Foo .__ Proto__, auf das zeigt? Warum können Sie nicht auf die Funktion foo selbst hinweisen? Obwohl die Funktion auch ein Objekt ist, werde ich ausführlich darüber sprechen, wenn Sie die Chance haben. Aber es ist sicherlich nicht angemessen, auf Foo .__ Proto__Foo hinzuweisen, da Foo eine Funktion mit viel logischem Code ist. Als Objekt hat es keine Bedeutung, logische Verarbeitung zu erben. Was es erben will, ist das Attribut des "Prototypenobjekts".
Daher generiert jede Funktion automatisch ein Prototyp -Objekt, und das __Proto__ des Objekts, das von dieser Funktion neu ist, zeigt auf den Prototyp dieser Funktion.
foo .__ proto__ -> foo.prototype
Zusammenfassen
Nachdem ich so viel gesagt habe, habe ich es immer noch nicht vollständig erklärt, daher ist es besser, im vorherigen Bild zu sein. Ich habe Bilder von anderen Internetnutzern bezogen, aber ich habe immer das Gefühl, dass ich nicht klar erklärt habe, also habe ich selbst ein Bild gezeichnet. Wenn ich denke, meins ist gut, bitte mögen Sie es! (Ich habe mein Bestes versucht, es zu zeichnen).
Nehmen wir dieses Bild auf und erinnern uns an die folgenden Fakten:
1. In jedem Objekt befindet sich ein _Proto_ -Attribut.
Es gibt kein Konzept einer Klasse (Schimmel) in der JS -Welt. Objekte werden von einem anderen Objekt (Proto) abgeleitet, sodass in jedem Objekt ein _proto_ -Attribut auf sein Prototypobjekt zeigt. (Siehe das Objekt OBJ, das in buchstäblicher Form in der oberen linken Ecke definiert ist. Es öffnet einen Raum, um die Eigenschaften des Objekts im Speicher zu speichern, und erzeugt ein _proto_, das auf seinen Prototyp hinweist - das obere Prototyp -Objekt.)
2. Jede Funktion hat eine Prototyp -Eigenschaft.
Warum wird "Konstruktor" als Konstruktor bezeichnet? Weil es ein Objekt konstruieren will. Nach der ersten Tatsache oben zeigt das Attribut _Proto_ des konstruierten neuen Objekts? Sie können nicht auf den Konstruktor selbst verweisen. Obwohl es sich auch um ein Objekt handelt, möchten Sie nicht, dass das neue Objekt die Eigenschaften und Methoden der Funktion erben. Daher hat jeder Konstruktor ein Prototypattribut, das auf ein Objekt als Prototyp des von diesem Konstruktors konstruierten neuen Objekts hinweist.
3. Funktionen sind auch Objekte.
Jede Funktion hat einige gemeinsame Eigenschaften und Methoden, wie z. B. anwenden ()/call () usw., aber wie werden diese gemeinsamen Methoden vererbt? Wie werden Funktionen erstellt? Stellen Sie sich vor, alles ist ein Objekt, einschließlich Funktionen, und ein Objekt, das durch einen Konstruktor konstruiert ist. Nach der zweiten Tatsache oben hat jede Funktion auch einen Prototyp, der auf ihren Konstruktor zeigt. Die Funktion dieses Konstruktors ist die Funktion, und alle Funktionen in JS sind aus der Funktion konstruiert. Die allgemeinen Eigenschaften und Funktionsmethoden werden in der Prototyp -Objektfunktion gespeichert.