Mit der regulären {...}
-Syntax können wir ein Objekt erstellen. Aber oft müssen wir viele ähnliche Objekte erstellen, wie zum Beispiel mehrere Benutzer oder Menüelemente und so weiter.
Dies kann mithilfe von Konstruktorfunktionen und dem "new"
-Operator erfolgen.
Konstruktorfunktionen sind technisch gesehen reguläre Funktionen. Es gibt jedoch zwei Konventionen:
Sie werden zuerst mit Großbuchstaben benannt.
Sie sollten nur mit dem Operator "new"
ausgeführt werden.
Zum Beispiel:
Funktion Benutzer(name) { this.name = Name; this.isAdmin = false; } let user = new User("Jack"); Alert(Benutzername); // Jack alarm(user.isAdmin); // FALSCH
Wenn eine Funktion mit new
ausgeführt wird, führt sie die folgenden Schritte aus:
Es wird ein neues leeres Objekt erstellt und this
zugewiesen.
Der Funktionskörper wird ausgeführt. Normalerweise wird this
geändert und neue Eigenschaften hinzugefügt.
Der Wert this
wird zurückgegeben.
Mit anderen Worten, new User(...)
macht so etwas wie:
Funktion Benutzer(name) { // this = {}; (implizit) // Eigenschaften hinzufügen this.name = Name; this.isAdmin = false; // das zurückgeben; (implizit) }
let user = new User("Jack")
das gleiche Ergebnis liefern wie:
let user = { Name: „Jack“, isAdmin: falsch };
Wenn wir nun andere Benutzer erstellen möchten, können wir new User("Ann")
, new User("Alice")
usw. aufrufen. Viel kürzer als jedes Mal Literale zu verwenden und außerdem leicht zu lesen.
Das ist der Hauptzweck von Konstruktoren – die Implementierung von wiederverwendbarem Objekterstellungscode.
Beachten wir noch einmal: Technisch gesehen kann jede Funktion (außer Pfeilfunktionen, da diese nicht über this
verfügen) als Konstruktor verwendet werden. Es kann mit new
ausgeführt werden und führt den oben genannten Algorithmus aus. Der „Großbuchstabe zuerst“ ist eine allgemeine Vereinbarung, um deutlich zu machen, dass eine Funktion mit new
ausgeführt werden soll.
neue Funktion() { … }
Wenn wir viele Codezeilen haben, die sich mit der Erstellung eines einzelnen komplexen Objekts befassen, können wir sie wie folgt in eine sofort aufgerufene Konstruktorfunktion einschließen:
// eine Funktion erstellen und diese sofort mit new aufrufen let user = new function() { this.name = "John"; this.isAdmin = false; // ...weiterer Code zur Benutzererstellung // vielleicht komplexe Logik und Aussagen // lokale Variablen usw };
Dieser Konstruktor kann nicht erneut aufgerufen werden, da er nirgendwo gespeichert, sondern nur erstellt und aufgerufen wird. Dieser Trick zielt also darauf ab, den Code, der das einzelne Objekt erstellt, ohne zukünftige Wiederverwendung zu kapseln.
Fortgeschrittene Sachen
Die Syntax aus diesem Abschnitt wird selten verwendet. Überspringen Sie ihn, es sei denn, Sie möchten alles wissen.
Innerhalb einer Funktion können wir mithilfe einer speziellen new.target
Eigenschaft überprüfen, ob sie mit new
oder ohne aufgerufen wurde.
Sie ist für reguläre Aufrufe undefiniert und entspricht der Funktion, wenn sie mit new
aufgerufen wird:
Funktion User() { alarm(new.target); } // ohne „neu“: Benutzer(); // undefiniert // mit „neu“: neuer Benutzer(); // Funktion Benutzer { ... }
Dies kann innerhalb der Funktion verwendet werden, um festzustellen, ob sie mit new
“ „im Konstruktormodus“ oder ohne „im regulären Modus“ aufgerufen wurde.
Wir können dazu auch sowohl new
als auch regelmäßige Anrufe tätigen, etwa so:
Funktion Benutzer(name) { if (!new.target) { // wenn du mich ohne new ausführst neuen Benutzer (Namen) zurückgeben; // ...ich füge Neues für Sie hinzu } this.name = Name; } let john = User("John"); // Leitet den Anruf an einen neuen Benutzer weiter alarm(john.name); // John
Dieser Ansatz wird manchmal in Bibliotheken verwendet, um die Syntax flexibler zu gestalten. Damit die Funktion mit oder ohne new
aufgerufen werden kann und sie trotzdem funktioniert.
Wahrscheinlich ist es jedoch nicht überall sinnvoll, es zu verwenden, da das Weglassen von new
es etwas weniger offensichtlich macht, was vor sich geht. Mit new
wissen wir alle, dass das neue Objekt erstellt wird.
Normalerweise verfügen Konstruktoren nicht über eine return
-Anweisung. Ihre Aufgabe ist this
, alle notwendigen Dinge hineinzuschreiben, und es wird automatisch das Ergebnis.
Wenn es jedoch eine return
-Anweisung gibt, ist die Regel einfach:
Wenn return
mit einem Objekt aufgerufen wird, wird das Objekt anstelle von this
zurückgegeben.
Wenn return
mit einem Grundelement aufgerufen wird, wird es ignoriert.
Mit anderen Worten: „ return
mit einem Objekt“ gibt dieses Objekt zurück, in allen anderen Fällen wird this
zurückgegeben.
Hier überschreibt beispielsweise return
this
indem es ein Objekt zurückgibt:
Funktion BigUser() { this.name = "John"; return { name: „Godzilla“ }; // <-- gibt dieses Objekt zurück } alarm( new BigUser().name ); // Godzilla, habe das Objekt
Und hier ist ein Beispiel mit einem leeren return
(oder wir könnten ein Grundelement dahinter platzieren, spielt keine Rolle):
Funktion SmallUser() { this.name = "John"; zurückkehren; // <-- gibt dies zurück } alarm( new SmallUser().name ); // John
Normalerweise haben Konstruktoren keine return
-Anweisung. Das besondere Verhalten bei zurückkehrenden Objekten erwähnen wir hier hauptsächlich der Vollständigkeit halber.
Klammern weglassen
Übrigens können wir die Klammern nach new
weglassen:
let user = neuer Benutzer; // <-- keine Klammern // das Gleiche wie let user = new User();
Das Weglassen von Klammern wird hier nicht als „guter Stil“ angesehen, die Syntax ist jedoch durch die Spezifikation zulässig.
Die Verwendung von Konstruktorfunktionen zum Erstellen von Objekten bietet ein hohes Maß an Flexibilität. Die Konstruktorfunktion kann über Parameter verfügen, die definieren, wie das Objekt erstellt wird und was darin eingefügt wird.
Natürlich können wir this
nicht nur Eigenschaften, sondern auch Methoden hinzufügen.
Beispielsweise erstellt new User(name)
unten ein Objekt mit dem angegebenen name
und der Methode sayHi
:
Funktion Benutzer(name) { this.name = Name; this.sayHi = function() { Alert( "Mein Name ist: " + this.name ); }; } let john = new User("John"); john.sayHi(); // Mein Name ist: John /* John = { Name: „John“, sayHi: function() { ... } } */
Um komplexe Objekte zu erstellen, gibt es eine fortgeschrittenere Syntax, Klassen, die wir später behandeln werden.
Konstruktorfunktionen oder kurz Konstruktoren sind reguläre Funktionen, es besteht jedoch allgemeiner Konsens darüber, sie zuerst mit Großbuchstaben zu benennen.
Konstruktorfunktionen sollten nur mit new
aufgerufen werden. Ein solcher Aufruf impliziert die Erstellung eines leeren this
am Anfang und die Rückgabe des gefüllten am Ende.
Wir können Konstruktorfunktionen verwenden, um mehrere ähnliche Objekte zu erstellen.
JavaScript bietet Konstruktorfunktionen für viele integrierte Sprachobjekte: wie Date
für Datumsangaben, Set
für Mengen und andere, die wir untersuchen möchten.
Objekte, wir kommen wieder!
In diesem Kapitel behandeln wir nur die Grundlagen zu Objekten und Konstruktoren. Sie sind wichtig, um in den nächsten Kapiteln mehr über Datentypen und Funktionen zu erfahren.
Nachdem wir das gelernt haben, kehren wir zu Objekten zurück und gehen in den Kapiteln Prototypen, Vererbung und Klassen ausführlicher auf sie ein.
Wichtigkeit: 2
Ist es möglich, die Funktionen A
und B
so zu erstellen, dass new A() == new B()
?
Funktion A() { ... } Funktion B() { ... } sei a = neues A(); sei b = neues B(); alarm( a == b ); // WAHR
Wenn ja, geben Sie ein Beispiel ihres Codes an.
Ja, das ist möglich.
Wenn eine Funktion ein Objekt zurückgibt, gibt new
es anstelle von this
zurück.
So können sie beispielsweise dasselbe extern definierte Objekt obj
zurückgeben:
sei obj = {}; Funktion A() { return obj; } Funktion B() { return obj; } alarm( neues A() == neues B() ); // WAHR
Wichtigkeit: 5
Erstellen Sie eine Konstruktorfunktion Calculator
, die Objekte mit drei Methoden erstellt:
read()
fordert zur Eingabe zweier Werte auf und speichert sie als Objekteigenschaften mit den Namen a
bzw. b
.
sum()
gibt die Summe dieser Eigenschaften zurück.
mul()
gibt das Multiplikationsprodukt dieser Eigenschaften zurück.
Zum Beispiel:
let Calculator = new Calculator(); Rechner.read(); Alert( "Sum=" + Rechner.sum() ); Alert( "Mul=" + Rechner.mul() );
Führen Sie die Demo aus
Öffnen Sie eine Sandbox mit Tests.
Funktion Calculator() { this.read = function() { this.a = +prompt('a?', 0); this.b = +prompt('b?', 0); }; this.sum = function() { return this.a + this.b; }; this.mul = function() { return this.a * this.b; }; } let Calculator = new Calculator(); Rechner.read(); Alert( "Sum=" + Rechner.sum() ); Alert( "Mul=" + Rechner.mul() );
Öffnen Sie die Lösung mit Tests in einer Sandbox.
Wichtigkeit: 5
Erstellen Sie eine Konstruktorfunktion Accumulator(startingValue)
.
Das erstellte Objekt sollte:
Speichern Sie den „aktuellen Wert“ in der Eigenschaft value
. Der Startwert wird auf das Argument des Konstruktors startingValue
gesetzt.
Die Methode read()
sollte prompt
verwenden, um eine neue Zahl zu lesen und sie zu value
hinzuzufügen.
Mit anderen Worten: Die Eigenschaft value
ist die Summe aller vom Benutzer eingegebenen Werte mit dem Anfangswert startingValue
.
Hier ist die Demo des Codes:
let accumulator = new Accumulator(1); // Anfangswert 1 accumulator.read(); // fügt den vom Benutzer eingegebenen Wert hinzu accumulator.read(); // fügt den vom Benutzer eingegebenen Wert hinzu alarm(accumulator.value); // zeigt die Summe dieser Werte
Führen Sie die Demo aus
Öffnen Sie eine Sandbox mit Tests.
Funktion Accumulator(startingValue) { this.value = StartingValue; this.read = function() { this.value += +prompt('Wie viel soll hinzugefügt werden?', 0); }; } let accumulator = new Accumulator(1); accumulator.read(); accumulator.read(); alarm(accumulator.value);
Öffnen Sie die Lösung mit Tests in einer Sandbox.