Vor kurzem schaue ich mir "JavaScript Advanced Programing" (zweite Ausgabe) an
Schaffung von Objekten in JavaScript
• Fabrikmodus
• Konstruktormodus
• Prototypmodus
• Kombinieren Sie das Konstruktor- und Prototypmuster
• Prototypendynamischer Modus
Die meisten objektorientierten Sprachen haben das Konzept einer Klasse, durch das mehrere Objekte mit denselben Methoden und Attributen erstellt werden können. Obwohl JavaScript technisch eine objektorientierte Sprache ist, hat JavaScript nicht das Konzept der Klassen, alles ist ein Objekt. Jedes Objekt ist eine Instanz eines bestimmten Referenztyps und wird durch vorhandene Referenztypen erstellt. Der Referenztyp kann nativ oder angepasst werden. Die nativen Referenztypen sind: Objekt, Array, Daten, Regexp, Funktion. ! Ein Referenztyp ist eine Datenstruktur, die Daten und Funktionen zusammen organisiert, die normalerweise als Klasse bezeichnet werden. In JavaScript, dem das Konzept der Klasse fehlt, ist das Problem, das gelöst werden muss, wie man Objekte effizient erstellt.
1.1.0. Allgemeine Methoden zum Erstellen von Objekten
var person = {}; // Objektliterale Darstellung entspricht Var Person = new objcect (); Person.name = 'evansdiy'; Person.age = '22'; Person.friends = ['Ajiao', 'Tiantian', 'Pangzi']; Person.Logname = function () {console.log (this.name);}Basierend auf dem Objektreferenztyp wird ein Objekt erstellt, das vier Eigenschaften enthält, von denen eine eine Methode ist. Wenn Sie viele Instanzen wie Person benötigen, gibt es viele doppelte Code.
1.1.1. Werksmodus [Top]
Erstellen Sie ein Objekt mit einer Funktion, die die Details des Objekts enthalten und dann das Objekt zurückgeben kann.
Funktionsperson (Name, Alter, Freunde) {var o = {Name: Name, Alter: Alter, Freunde: Freunde, logName: function () {console.log (this.name); }}; return o;} var person1 = person ('evansdiy', '22', ['ajiao', 'Tiantian', 'pangzi']);Jedes Mal, wenn die Personfunktion aufgerufen wird, wird ein neues Objekt über das Objekt O in der Funktion erstellt und dann zurückgegeben. Abgesehen davon gibt es dieses interne Objekt o, um ein neues Objekt zu erstellen, keinen anderen Zweck. Darüber hinaus ist es unmöglich, den vom Werksmodus erstellten Objekttyp zu bestimmen.
1.1.2.Constructor -Modus [Top]
Funktionsperson (Name, Alter, Job) {this.name = name; this.age = Alter; this.job = Job; this.Logname = function () {console.log (this.name); }} // Erstellen Sie eine Instanz der Person durch den neuen Operator var person1 = new Person ('boy-a', '22', 'Arbeiter'); var person2 = new Person ('Mädchen-B', '23', 'Lehrer'); Person1.Logname (); //boy-aperson2.Logname (); // Girl-aWenn wir den Fabrikmodus vergleichen, können wir feststellen, dass hier keine Zwischenobjekte erstellt werden müssen, sondern keine Rückkehr. Darüber hinaus kann die Instanz des Konstruktors als spezifischer Typ identifiziert werden, der das Problem der Objekterkennung löst (indem das Konstruktorattribut der Instanz überprüft wird oder den Instanzoperator verwendet, um zu überprüfen, ob die Instanz von einem Konstruktor erstellt wird).
console.log (Person1.Constructor == Person); // Konstruktor befindet sich im Konstruktorprototyp und zeigt auf den Konstruktor, und das Ergebnis ist wahr
console.log (Person1 -Instanz der Person); // Verwenden Sie den Instanz des Operators, um festzustellen, ob Person1 eine Instanz der Konstruktor -Person ist, das Konstruktormuster hat jedoch auch seine eigenen Probleme. Tatsächlich wird die Logname -Methode in jeder Instanz einmal nachgebaut. Es ist zu beachten, dass die durch Instanziierung erstellten Methoden nicht gleich sind und der folgende Code falsch wird:
console.log (Person1.Logname == Person2.Logname); // false Wir können die Methode außerhalb des Konstruktors (in eine globale Funktion geändert) verschieben, um dieses Problem zu lösen:
Funktion logName () {console.log (this.name);} Funktion Logage () {console.log (this.age);};Globale globale Funktionen, die weltweit erstellt wurden, können jedoch nur durch Instanzen aufgerufen werden, die von Person erstellt wurden, was etwas unrealistisch ist. Wenn es viele Methoden gibt, müssen sie nacheinander immer noch definiert werden, ohne dass die Verkapselung fehlt.
1.1.3.Prototypenmodus [Top]
Jede Funktion in JavaScript enthält einen Zeiger auf das Prototyp -Attribut (die meisten Browser können über das interne Attribut __Proto__ darauf zugreifen. Ein Prototyp -Attribut ist ein Objekt, das Eigenschaften und Methoden enthält, die von allen von einem bestimmten Referenztyp erstellten Instanzen geteilt werden.
Funktion person () {} person.name = 'evansdiy'; person.Prototype.friends = ['ajiao', 'Jianjian', 'pangzi']; person.Prototype.Logname = function () {console.log (this.name);} var person1 = new Person ();Der obige Code macht folgende Dinge:
1. Definieren Sie eine Konstruktor -Person. Die Personfunktion erhält automatisch eine Prototyp -Eigenschaft. Diese Eigenschaft enthält nur eine Konstruktoreigenschaft, die standardmäßig auf die Person zeigt.
2. Fügen Sie drei Attribute über Person hinzu.
3. Erstellen Sie eine Instanz der Person und rufen Sie dann die Methode LOGNAME () auf der Instanz auf.
Was Sie hier beachten müssen, ist der aufrufende Prozess der LogName () -Methode:
1. Sehen Sie sich die LogName () -Methode in der Person1 -Instanz nach und stellten fest, dass es keine solche Methode gibt, daher habe ich mich auf den Prototyp von Person1 zurückgezogen1
2. Suchen Sie nach der Logame () -Methode im Prototyp von Person11. Es gibt diese Methode. Deshalb nennen wir diese Methode basierend auf einem solchen Suchprozess. Wir können verhindern, dass die Instanz auf das gleichnamige Attribut im Prototyp zugreift, indem wir das gleichnamige Attribut im Prototyp der Instanz definieren. Es ist zu beachten, dass dies nicht das gleichnamige Attribut des Prototyps löscht, sondern nur die Instanz verhindert.
var person2 = new Person ();
Person2.name = 'laocai'; Wenn wir keine Eigenschaften mehr für die Instanz benötigen, können wir sie über den Löschbetreiber löschen.
Person löschen2.Name; Verwenden Sie die For-In-Schleife, um alle Attribute aufzuzählen, auf die eine Instanz zugreifen kann (unabhängig davon, ob das Attribut in der Instanz oder im Prototyp vorliegt):
für (i persönlich) {console.log (i);}Gleichzeitig können Sie auch die Methode von HasownProperty () verwenden, um festzustellen, ob eine bestimmte Eigenschaft auf der Instanz oder im Prototyp vorhanden ist. Nur wenn das Eigentum in der Instanz existiert, wird der wahr zurückgegeben:
console.log (person1.hasownProperty ('name')); // true! HasownProperty stammt aus dem Prototyp des Objekts und ist der einzige Weg in JavaScript, die Prototyp -Kette bei Verarbeitungseigenschaften nicht nachzuschlagen. [Über JavaScript Secret Garden] Außerdem können Sie auch die Methode In Operator und HasownProperty () verwenden, um festzustellen, ob in der Instanz oder im Prototyp eine bestimmte Eigenschaft vorhanden ist:
console.log (('Freunde' persönlich) &&! person1.hasownProperty ('Freunde'); zuerst bestimmen, ob Person1 auf das Eigentum von Freunden zugreifen kann. Wenn möglich, bestimmen Sie, ob diese Eigenschaft in der Instanz vorliegt (beachten Sie die vorherige!). Wenn es in der Instanz nicht existiert, bedeutet dies, dass diese Eigenschaft im Prototyp vorliegt. Wie bereits erwähnt, ist der Prototyp auch ein Objekt, sodass wir den Prototyp unter Verwendung einer Objektliteraldarstellung schreiben können. Die vorherige Schreibmethode zum Hinzufügen von Code zum Prototyp kann geändert werden, um:
Person.Prototype = {name: 'evansdiy', Freunde: ['ajiao', 'jianjian', 'pangzi'], logname: function () {console.log (this.name); }}Da das Objektliteralsyntax den gesamten Prototyp -Prototyp neu schreibt, zeigt das Konstruktorattribut, das beim Erstellen des Konstruktors standardmäßig erhalten wurde, auf den Objektkonstruktor:
// Nach dem Objekt, das wörtlich den Prototyp umschreibt
console.log (Person1.Constructor); // Objekt gibt jedoch der Instanzbetreiber das gewünschte Ergebnis weiter:
// Nach dem Objekt, das wörtlich den Prototyp umschreibt
console.log (Person1 -Instanz von Person); // true natürlich können Sie den Konstruktorwert im Prototyp manuell festlegen, um dieses Problem zu lösen.
Person.Prototype = {Konstruktor: Person, ......}Wenn das Prototyp -Objekt nach Erstellen der Objektinstanz geändert wird, wird die Änderung des Prototyps sofort in allen Objektinstanzen reflektiert:
Funktion person () {}; var person1 = new Person (); Person.Prototype.name = 'evansdiy'; console.log (Person1.Name); // 'evansdiy' 'Die Verbindung zwischen einer Instanz und einem Prototyp ist nur ein Zeiger, keine Kopie des Prototyps. Der Prototyp ist tatsächlich ein Suchprozess. Alle Änderungen am Prototypobjekt werden in allen Objektinstanzen reflektiert, auch wenn der Prototyp nach Erstellen der Instanz geändert wird. Was ist, wenn das Prototypobjekt nach dem Erstellen einer Objektinstanz umschreibt?
Funktion person () {}; var person1 = new Person1 (); // Die erstellte Instanz bezieht sich auf den ursprünglichen Prototyp // Die Prototype Person.Prototype = {Freunde: ['ajiao', 'jianjian', 'pangzi']} var person2 = new person (); console.log (Person1.freunde);Der obige Code hat einen undefinierten Fehler, wenn er in die letzte Zeile ausgeführt wird. Wenn wir für das In-In die zugänglichen Eigenschaften persönlich aufzählen1, werden wir feststellen, dass nichts im Inneren ist, aber Person2 kann auf das Attribut für Freunde auf dem Prototyp zugreifen. ! Das Umschreiben des Prototyps schneidet die Verbindung zwischen dem vorhandenen Prototyp und allen zuvor erstellten Objektinstanzen ab. Der Prototyp der zuvor erstellten Objektinstanz ist noch da, ist aber alt.
// Beim Erstellen von Person1 wurde das Prototyp -Objekt noch nicht umgeschrieben, sodass der Konstruktor im Prototyp -Objekt immer noch die Standardperson ist ()
console.log (Person1.Constructor); // Person ()
// Aber der Konstruktor von Person2 zeigt auf Objekt ()
console.log (Person2.Constructor); // Object () Es ist zu beachten, dass das Prototypmuster den Prozess der Übergabe von Parametern für den Konstruktor ignoriert und alle Instanzen den gleichen Attributwert erhalten. Gleichzeitig gibt es ein großes Problem mit dem Prototypmuster, dh der Referenztypwert im Prototyp -Objekt wird von allen Instanzen gemeinsam genutzt, und die Änderung des Referenztypwerts wird auch in allen Objektinstanzen reflektiert.
Funktion person () {}; person.Prototype = {Freunde: ['ajiao', 'Tiantian', 'pangzi']} var person1 = new Person (); var person2 = new Person (); person1.friends.push ('laocai'); console.log (person2.friends);Das Ändern des Referenztypwerts von Person1 -Freunden bedeutet, dass sich die Freunde persönlich auch ändern werden. Tatsächlich sind die im Prototyp gespeicherten Freunde eigentlich nur ein Zeiger auf den Wert der Freunde im Haufen (die Länge dieses Zeigers wird auf dem Stapel festgelegt und gespeichert). Wenn auf eine Instanz über den Prototyp auf den Wert des Referenztyps zugreift, wird er auch vom Zeiger zugegriffen, anstatt auf die Kopie auf der jeweiligen Instanz zugreifen zu können (eine solche Kopie existiert nicht).
1.1.4. Erstellen Sie ein Objekt in Kombination mit Konstruktor- und Prototypmuster [Top]
Kombinieren Sie die Vorteile des Konstruktor- und Prototypmodus, machten ihre jeweiligen Mängel aus, verwendeten Konstrukteure zum Übergeben von Initialisierungsparametern, Definieren von Instanzattributen darin und verwenden Prototypen zur Definition gemeinsamer Methoden und öffentlichen Attribute. Dieser Modus wird am häufigsten verwendet.
Funktionsperson (Name, Alter) {this.name = name; this.age = Alter; this.friends = ['ajiao', 'jianjian', 'pangzi'];} person.prototype = {constructor: person, logname: function () {console.log (this.name); }} var person1 = new Person ('evansdiy', '22'); var person2 = new Person ('amy', '21'); Person1.Logname (); // 'evansdiy'person1.friends.push (' haixao '); console.log (person2.lhens.lhenlänge); // // 3 3);1.1.5.Prototypen dynamischer Modus [TOP]
Der dynamische Prototypenmodus enthält alle in den Konstruktor erforderlichen Informationen und verwendet die IF -Anweisung, um festzustellen, ob eine bestimmte Eigenschaft im Prototyp vorliegt. Wenn es nicht vorhanden ist (wenn der Konstruktor zum ersten Mal aufgerufen wird), führen Sie den Prototyp -Initialisierungscode in der IF -Anweisung aus.
Funktionsperson (Name, Alter) {this.name = name; this.age = Alter; if (typeof this.Logname! }; Person.Prototype.logage = function () {console.log (this.age); }; }; };} var person1 = new Person ('evansdiy', '22'); // Der Konstruktor wurde zum ersten Mal gerufen, und der Prototyp wurde zu diesem Zeitpunkt geändert. var person2 = new Person ('Amy', '21'); // Die LogName () -Methode existiert bereits und der Prototyp wird nicht erneut geändertEs ist zu beachten, dass dieses Muster die Objektliteral -Syntax nicht zum Schreiben von Prototypobjekten verwenden kann (so überschreibt dies die Prototypobjekte). Wenn der Prototyp umgeschrieben wird, enthält das vom Konstruktor erstellte Prototyp -Objekt, das für die erste Instanz erstellt wurde, die Prototyp -Objekteigenschaften in der IF -Anweisung nicht.
Funktionsperson (Name, Alter) {this.name = name; this.age = Alter; if (typeof this.Logname! }, Logage: function () {console.log (this.age); }}}};} var person1 = new Person ('evansdiy', '22'); var person2 = new Person ('Amy', '21'); Person2.Logname (); // 'Amy'person1.Logname (); // Logname () -Methode existieren nichtEs ist zu beachten, dass jedes Modell seine eigenen Anwendungsszenarien hat, und es spielt keine Rolle bei seinen Vor- und Nachteilen.
Die obige kurze Analyse der verschiedenen Modi des Erstellens von Objekten in JavaScript ist der gesamte Inhalt, den ich mit Ihnen teile. Ich hoffe, es kann Ihnen eine Referenz geben und ich hoffe, Sie können Wulin.com mehr unterstützen.