Heim > Artikel > Web-Frontend > JavaScript-Prototypen verstehen
Javascript-Prototypen sorgen immer für Verwirrung, egal ob es sich um erfahrene Experten oder den Autor selbst handelt, ich denke, diese Art von Verwirrung beginnt, wenn wir zum ersten Mal mit Prototypen in Berührung kommen beziehen sich häufig auf neue und Konstruktoreigenschaften, insbesondere auf die Prototypeigenschaften von Funktionen. Tatsächlich ist ein Prototyp ein sehr einfaches Konzept. Um es besser zu verstehen, sollten wir uns zunächst an das Prinzip erinnern, das zu vergessen, was wir über Konstruktorprototypen gelernt haben.
Was ist ein Prototyp?
Ein Prototyp ist ein Objekt, über das andere Objekte die Eigenschaftsvererbung implementieren können.
Kann jedes Objekt ein Prototyp werden?
ist
Welche Objekte haben Prototypen
Alle Objekte haben standardmäßig einen Prototyp, da der Prototyp selbst auch ein Objekt ist, sodass jeder Prototyp selbst einen Prototyp hat Prototyp (mit Mit einer Ausnahme befindet sich der Standardobjektprototyp an der Spitze der Prototypenkette. Weitere Informationen zur Prototypenkette finden Sie später >In JavaScript ist ein Objekt eine Sammlung beliebiger ungeordneter Schlüssel-Wert-Paare. Wenn es kein primärer Datentyp ist (undefiniert, null, boolesch, Zahl oder Zeichenfolge), dann ist es ein Objekt
Sie sagte, dass jedes Objekt einen Prototyp hat, aber als ich es als ({}).prototype schrieb, bekam ich eine Null. Hast du recht?
Vergessen Sie alles, was Sie über Prototypeneigenschaften gelernt haben, es könnte der Grund für Ihre Verwirrung über Prototypen sein. Der wahre Prototyp eines Objekts wird von der Eigenschaft [[Prototype]] innerhalb des Objekts gespeichert. ECMA hat den Standard-Objektprototyp-Accessor Object.getPrototype(object) eingeführt, bisher haben nur Firefox und Chrome diesen Accessor implementiert. Zusätzlich zum IE unterstützen auch andere Browser den nicht standardmäßigen Accessor __proto__. Wenn keiner dieser Schritte funktioniert, müssen wir sein Prototypattribut im Konstruktor des Objekts finden. Der folgende Code zeigt die Methode zum Abrufen des Objektprototyps
var a = {};
//Firefox 3.6 und Chrome 5
Object.getPrototypeOf(a); //[object Objekt ]
//Firefox 3.6, Chrome 5 und Safari 4
a.__proto__; //[object Object]
//alle Browser
a .constructor.prototype; //[object Object]
ok, alles läuft gut, aber false ist offensichtlich ein Hauptdatentyp, aber false.__proto__ gibt einen Wert zurück
Wenn Sie versuchen, ihn zu bekommen der Prototyp eines primären Datentyps, er wurde in ein Objekt umgewandelt
//(funktioniert auch im IE, aber nur durch Zufall)
false .__proto__ === Boolean (falsch). __proto__; //true
Ich möchte Prototypen in der Vererbung verwenden, also wie soll ich das machen?
Es macht wenig Sinn, einen Prototyp nur für eine Instanz zu verwenden. Dies ist dasselbe wie das direkte Hinzufügen von Eigenschaften zu dieser Instanz. Wenn wir bereits ein Instanzobjekt erstellt haben, möchten wir ein vorhandenes erben . Die Funktion eines Objekts, wie z. B. Array, können wir wie folgt ausführen (in Browsern, die __proto__ unterstützen)
//ungewöhnlicher Fall und funktioniert nicht im IE
var a = {};
a. __proto__ = Array.prototype;
a.length; //0
——————————————————————————— — ———–
Anmerkung des Übersetzers: Im obigen Beispiel wird zuerst ein Objekt a erstellt, und dann wird die Funktion des Erbens des vorhandenen Objektarrays durch den Prototyp von a erreicht
—————— —— ——————————————————————————————
Der wahre Charme von Prototypen liegt darin, dass mehrere Instanzen einen gemeinsamen Prototyp teilen. Sobald die Eigenschaften eines Prototypobjekts (Hinweis: das Objekt, auf das der Prototyp eines Objekts verweist) definiert sind, können sie von mehreren Instanzen geerbt werden, die darauf verweisen (Hinweis: das heißt, die Prototypen dieser Instanzobjekte verweisen auf). die Bedeutung dieses Vorgangs in Bezug auf Leistung und Wartung liegt auf der Hand
Ist dies auch der Grund für die Existenz des Konstruktors?
Ja. Konstruktoren bieten einen praktischen browserübergreifenden Mechanismus, der es ermöglicht, einen gemeinsamen Prototyp für Instanzen bereitzustellen, wenn sie erstellt werden.
Bevor Sie ein Beispiel bereitstellen können, muss ich wissen, was die Eigenschaft „constructor.prototype“ eigentlich ist Es?
Zuallererst unterscheidet JavaScript nicht zwischen Konstruktoren und anderen Funktionen, daher verfügt jede Funktion über ein Prototypattribut. Wäre es umgekehrt keine Funktion, gäbe es keine solche Eigenschaft. Bitte sehen Sie sich den Code unten an
//Funktion wird niemals ein Konstruktor sein, hat aber trotzdem eine Prototypeigenschaft
Math.max.prototype; //[object Object]
//Funktion, die als Konstruktor gedacht ist, hat auch einen Prototyp
var A = function (name) {
this .name = name;
}
A.prototype; //[object Object]
//Math ist keine Funktion, also keine Prototypeigenschaft
Math.prototype; //null
Jetzt können wir eine Definition erstellen: Die Prototypeigenschaft der Funktion A ist ein Objekt, wenn dies eine Funktion ist Wird als Konstruktor zum Erstellen einer Instanz verwendet, wird das Prototypattribut der Funktion allen Objektinstanzen als Prototyp zugewiesen (Hinweis: Die Prototypen aller Instanzen beziehen sich auf die Prototypattribute der Funktion)
————— — ——————————————————————————————-
Anmerkung des Übersetzers: Der folgende Code erklärt das alles ausführlicher
//Erstellen Sie eine Funktion b
var b = function(){ var one;🎜>//Verwenden Sie b, um eine Objektinstanz c zu erstellen
var c = new b();
// Die Konstruktoren von b und c anzeigen
b.constructor; // function Function() { [native code]}
b.constructor==Function.constructor; //true
c.constructor; // Der Konstruktor der Instanz c ist b function(){ var one; }
c.constructor==b //true
//b ist eine Funktion, überprüfen Sie den Prototyp von b wie folgt
b .constructor.prototype // function (){}
b.__proto__ //function (){}
//b ist eine Funktion, da JavaScript nicht zwischen dem Konstruktor und der Funktion unterscheidet function Wie der Konstruktor hat
//ein Prototypattribut, das sich vom Prototyp der Funktion (b.__proto__ oder b.construtor.prototype) unterscheidet.
b.prototype //[object Object] Der Prototyp der Funktion b Property
b.prototype==b.constructor.prototype //fasle
b.prototype==b.__proto__ //false
b.__proto__==b.constructor.prototype // true
//c ist eine von b erstellte Objektinstanz. Sehen Sie sich den Prototyp von c wie folgt an:
c.constructor.prototype //[object Object] Dies ist der Prototyp des Objekts
c .__proto__ // [object Object] Dies ist der Prototyp des Objekts
c.constructor.prototype==b.constructor.prototype; //false Vergleiche den Prototyp von c und den Prototyp von b
c.constructor.prototype==b .prototype; //true Vergleichen Sie die Prototypeigenschaften von c und die Prototypeigenschaften von b
//Fügen Sie ein Attribut hinzu max
b.prototype.max = 3
//Instanz c für die Prototypeigenschaft der Funktion b Es gibt auch ein Attribut max
c.max //3
Im obigen Beispiel ist der Prototyp der Objektinstanz c derselbe wie das Prototypattribut von die Funktion b. Wenn das Prototypattribut von b geändert wird, ändert sich auch der Prototyp der Objektinstanz c
——————————————————— ———————————————-
Verstehen Es ist uns wichtig, dass die Prototypeigenschaft einer Funktion nichts mit dem tatsächlichen Prototyp zu tun hat
//(Beispiel schlägt im IE fehl)
var A = function (name ) {
this .name = name;
}
A.prototype == A.__proto__; //false
A.__proto__ == Function.prototype; //true – Der Prototyp von A wird auf die Prototypeigenschaft seines Konstruktors gesetzt
Geben Sie mir ein Beispiel
Sie haben möglicherweise schon Hunderte Male Javascript wie dieses verwendet Mal und jetzt, wenn Sie es wieder sehen. Beim Codieren haben Sie möglicherweise unterschiedliche Verständnisse.
//Konstruktor. dieses wird als neues Objekt zurückgegeben und seine interne [[Prototyp]]-Eigenschaft wird auf die Standard-Prototypeneigenschaft des Konstruktors gesetzt
var Circle = function (radius) {
this .radius = radius;
//nächste Zeile ist implizit, nur zur Veranschaulichung hinzugefügt
//this.__proto__ = Circle.prototype;
}
//Erweitern Sie die Standard-Prototypeneigenschaft von Circle und erweitern Sie dadurch den Prototyp jeder generierten Instanz
Circle.prototype.area = function () {
return Math.PI* this .radius* this .radius;
}
//zwei Instanzen eines Kreises erstellen und jeweils den gemeinsamen Prototyp nutzen
var a = new Circle(3), b = new Circle(4);
a.area().toFixed(2 ); //28.27
b.area().toFixed(2); //50.27
Super. Wenn ich den Prototyp eines Konstruktors ändere, bedeutet das, dass bereits vorhandene Instanzen dieses Konstruktors die neueste Version des Konstruktors erhalten?
Nicht unbedingt. Wenn eine Prototypeigenschaft geändert wird, treten solche Änderungen auf. Weil a.__proto__ ein Verweis auf A.prototype ist, nachdem a tatsächlich erstellt wurde.
var A = function (name) {
this .name = name;
}
var a = new A( 'alpha' );
a.name; 'alpha'
A.prototype.x = 23;
a.x>————————————————————— —————————
Anmerkung des Übersetzers: Dies ist dasselbe wie im obigen Beispiel. Der Prototyp (a.__proto__) des Instanzobjekts a ist eine Referenz auf das Prototypattribut (A.prototype) der Funktion A, also wenn das, was geändert wird, das Prototypattribut von A ist,
Die Änderung wirkt sich auf die von A erstellte Objektinstanz a aus. Im folgenden Beispiel wird der Prototyp der Funktion A geändert, spiegelt sich jedoch nicht in der von A erstellten Instanz a wider.
var A = function(name )
{
this.name = name;
}
var a = new A('alpha');
a.name; //'alpha'
A.__proto__.max = 19880716;
a.max //undefiniert
————————————————————— —— ————————
Aber wenn ich jetzt das Prototypattribut von A durch ein neues Objekt ersetze, verweist der Prototyp a.__proto__ des Instanzobjekts immer noch auf den ursprünglichen Prototyp von A, als er erstellt wurde Attribut
var A = function (name) {
this .name = name;
}
var a = new A( 'alpha' );
a.name; /'alpha'
A.prototype = {x:23}; //null
———————————— ————————————————
Anmerkung des Übersetzers: Das heißt, wenn das Objekt, auf das das Prototypattribut der Funktion zeigt, nach der Erstellung der Instanz geändert wird, d. h. wenn die Wenn eine Instanz erstellt wird, wird das Objekt, auf das der Instanzprototyp zeigt, geändert. Dies hat jedoch keine Auswirkungen auf den Prototyp der bereits erstellten Instanz.
———————————————————————————————————————-
Ein Standard Wie sieht der Prototyp aus?
var A = function () {};
A.prototype.constructor == A; //true
var a = new A();
a.constructor == A ; //true (die Konstruktor-Eigenschaft von a wurde von seinem Prototyp geerbt)
Was ist die Beziehung zwischen Instanz von und Prototyp
Wenn der Prototyp von a zur Prototypenkette von A gehört, ist der Ausdruck eine Instanz von A ist wahr. Das bedeutet, dass wir die Instanz von austricksen können, sodass sie nicht funktioniert = A.prototype; //true – also gibt die Instanz von A true
eine Instanz von A zurück; //true; __proto__ = Function.prototype;
//a's Prototyp nicht mehr in derselben Prototypkette wie A's Prototypeigenschaft
eine Instanz von A; //false
Was kann man sonst noch mit Prototypen machen? Was ?
Denken Sie daran, dass jeder Konstruktor, den ich erwähnt habe, ein Prototypattribut hat, das verwendet wird, um den Prototyp für jede von ihm erstellte Instanz bereitzustellen. Dies gilt auch für den ursprünglichen Konstruktor Function, String usw. Durch die Erweiterung dieses Attributs können wir alle Instanzen des angegebenen Konstruktors erweitern
Ich habe diese Technik in vielen früheren Artikeln verwendet, um die Funktionserweiterung zu demonstrieren. Alle String-Instanzen im Tracer-Dienstprogramm-Artikel implementieren die Times-Methode, die den String selbst für eine bestimmte Anzahl von Malen kopiert.
String.prototype.times = function (count) {
return count < '' : new Array(count + 1).join( this );
}
"hello!" .times(3); //"hello!hello!hallo!";
"bitte..." .times(6); //"bitte...bitte...bitte...bitte...bitte...bitte..."
Sag mir, wie Vererbung funktioniert mit Prototypen. Was ist eine Prototypenkette?
Weil jedes Objekt und jeder Prototyp einen Prototyp hat (Hinweis: Ein Prototyp ist auch ein Objekt. Der Prototyp des Objekts zeigt auf das übergeordnete Objekt und der Prototyp des übergeordneten Objekts.) Zeigt auf das übergeordnete Element des übergeordneten Elements. Diese Beziehung, die Schicht für Schicht durch Prototypen verbunden ist, wird als Prototypenkette bezeichnet. Das Ende dieser Kette ist immer der Standardobjektprototyp.
a.__proto__ = b;
b.__proto__ = c;
c.__proto__ = {}; //Standardobjekt
{}. __proto__.__proto__; //null
Der Prototyp-Vererbungsmechanismus erfolgt intern und ist implizit. Wenn Sie den Wert des Attributs foo eines Objekts a erhalten möchten, sucht Javascript nach der Existenz von foo in der Prototypenkette Gefunden Der Wert von foo wird zurückgegeben, andernfalls wird undefiniert zurückgegeben.
Was ist mit der Aufgabe?
Prototyp-Vererbung ist kein Player. Wenn der Attributwert auf a.foo=’bar’ gesetzt ist, wird ein Wertbalken direkt auf das Attribut foo von a gesetzt. Um einem Prototyp eine Eigenschaft hinzuzufügen, müssen Sie den Prototyp direkt angeben.