In JavaScript ist eine Funktion keine „magische Sprachstruktur“, sondern ein besonderer Wert.
Die Syntax, die wir zuvor verwendet haben, wird Funktionsdeklaration genannt:
Funktion sayHi() { alarm( "Hallo" ); }
Es gibt eine andere Syntax zum Erstellen einer Funktion, die als Funktionsausdruck bezeichnet wird.
Es ermöglicht uns, in der Mitte eines beliebigen Ausdrucks eine neue Funktion zu erstellen.
Zum Beispiel:
let sayHi = function() { alarm( "Hallo" ); };
Hier können wir sehen, wie eine Variable sayHi
einen Wert erhält, die neue Funktion, erstellt als function() { alert("Hello"); }
.
Da die Funktionserstellung im Kontext des Zuweisungsausdrucks (rechts von =
) erfolgt, handelt es sich um einen Funktionsausdruck .
Bitte beachten Sie, dass hinter dem function
kein Name steht. Für Funktionsausdrücke ist das Weglassen eines Namens zulässig.
Hier weisen wir es sofort der Variablen zu, daher ist die Bedeutung dieser Codebeispiele dieselbe: „Erstellen Sie eine Funktion und fügen Sie sie in die Variable sayHi
ein“.
In komplexeren Situationen, auf die wir später stoßen werden, kann eine Funktion erstellt und sofort aufgerufen oder für eine spätere Ausführung geplant werden, nirgendwo gespeichert werden und somit anonym bleiben.
Um es noch einmal zu wiederholen: Ganz gleich, wie die Funktion erstellt wird, eine Funktion ist ein Wert. In beiden obigen Beispielen wird eine Funktion in der Variablen sayHi
gespeichert.
Wir können diesen Wert sogar mit der alert
ausdrucken:
Funktion sayHi() { alarm( "Hallo" ); } alarm( sayHi ); // zeigt den Funktionscode
Bitte beachten Sie, dass die letzte Zeile die Funktion nicht ausführt, da nach sayHi
keine Klammern stehen. Es gibt Programmiersprachen, in denen jede Erwähnung eines Funktionsnamens dessen Ausführung auslöst, aber JavaScript ist nicht so.
In JavaScript ist eine Funktion ein Wert, daher können wir sie als Wert behandeln. Der obige Code zeigt seine String-Darstellung, bei der es sich um den Quellcode handelt.
Sicherlich ist eine Funktion ein besonderer Wert in dem Sinne, dass wir sie wie sayHi()
nennen können.
Aber es ist immer noch ein Wert. Wir können damit wie mit anderen Arten von Werten arbeiten.
Wir können eine Funktion in eine andere Variable kopieren:
Funktion sayHi() { // (1) erstellen alarm( "Hallo" ); } let func = sayHi; // (2) kopieren func(); // Hallo // (3) Führen Sie die Kopie aus (es funktioniert)! sayHi(); // Hallo // das funktioniert auch immer noch (warum sollte es nicht)
Folgendes passiert oben im Detail:
Die Funktionsdeklaration (1)
erstellt die Funktion und fügt sie in die Variable namens sayHi
ein.
Zeile (2)
kopiert es in die Variable func
. Bitte beachten Sie noch einmal: Nach sayHi
stehen keine Klammern. Wenn ja, dann würde func = sayHi()
das Ergebnis des Aufrufs sayHi()
in func
schreiben, nicht die Funktion sayHi
selbst.
Jetzt kann die Funktion sowohl als sayHi()
als auch als func()
aufgerufen werden.
Wir hätten auch einen Funktionsausdruck verwenden können, um sayHi
in der ersten Zeile zu deklarieren:
let sayHi = function() { // (1) create alarm( "Hallo" ); }; let func = sayHi; // ...
Alles würde gleich funktionieren.
Warum steht am Ende ein Semikolon?
Sie fragen sich vielleicht, warum Funktionsausdrücke ein Semikolon haben ;
am Ende, Funktionsdeklarationen jedoch nicht:
Funktion sayHi() { // ... } let sayHi = function() { // ... };
Die Antwort ist einfach: Ein Funktionsausdruck wird hier als function(…) {…}
innerhalb der Zuweisungsanweisung erstellt: let sayHi = …;
. Das Semikolon ;
wird am Ende der Anweisung empfohlen, es ist nicht Teil der Funktionssyntax.
Das Semikolon wäre für eine einfachere Zuweisung da, etwa let sayHi = 5;
, und es ist auch für eine Funktionszuweisung da.
Schauen wir uns weitere Beispiele für die Übergabe von Funktionen als Werte und die Verwendung von Funktionsausdrücken an.
Wir schreiben eine Funktion ask(question, yes, no)
mit drei Parametern:
question
Text der Frage
yes
Funktion, die ausgeführt wird, wenn die Antwort „Ja“ lautet.
no
Funktion, die ausgeführt wird, wenn die Antwort „Nein“ lautet.
Die Funktion sollte die question
stellen und je nach Antwort des Benutzers yes()
oder no()
aufrufen:
Funktion ask(question, ja, nein) { if (bestätigen(frage)) ja() sonst nein(); } Funktion showOk() { Alert( "Sie haben zugestimmt." ); } Funktion showCancel() { Alert( „Sie haben die Ausführung abgebrochen.“ ); } // Verwendung: Funktionen showOk, showCancel werden als Argumente an ask übergeben ask("Sind Sie einverstanden?", showOk, showCancel);
In der Praxis sind solche Funktionen durchaus nützlich. Der Hauptunterschied zwischen einer echten ask
und dem obigen Beispiel besteht darin, dass reale Funktionen komplexere Methoden zur Interaktion mit dem Benutzer verwenden als eine einfache confirm
. Im Browser zeichnen solche Funktionen meist ein ansprechendes Fragefenster. Aber das ist eine andere Geschichte.
Die Argumente showOk
und showCancel
von ask
werden Callback-Funktionen oder einfach Callbacks genannt.
Die Idee ist, dass wir eine Funktion übergeben und erwarten, dass sie später bei Bedarf „zurückgerufen“ wird. In unserem Fall wird showOk
zum Rückruf für die Antwort „Ja“ und showCancel
für die Antwort „Nein“.
Wir können Funktionsausdrücke verwenden, um eine äquivalente, kürzere Funktion zu schreiben:
Funktion ask(question, ja, nein) { if (bestätigen(frage)) ja() sonst nein(); } fragen( "Sind Sie einverstanden?", function() { Alert("Sie haben zugestimmt."); }, function() { Alert("Sie haben die Ausführung abgebrochen."); } );
Hier werden Funktionen direkt im ask(...)
-Aufruf deklariert. Sie haben keinen Namen und werden daher anonym genannt. Auf solche Funktionen kann außerhalb von ask
nicht zugegriffen werden (da sie keinen Variablen zugewiesen sind), aber genau das wollen wir hier.
Dieser Code erscheint in unseren Skripten ganz natürlich, ganz im Sinne von JavaScript.
Eine Funktion ist ein Wert, der eine „Aktion“ darstellt.
Reguläre Werte wie Zeichenfolgen oder Zahlen repräsentieren die Daten .
Eine Funktion kann als Aktion wahrgenommen werden.
Wir können es zwischen Variablen übergeben und ausführen, wann immer wir wollen.
Lassen Sie uns die wichtigsten Unterschiede zwischen Funktionsdeklarationen und Ausdrücken formulieren.
Erstens die Syntax: Wie man sie im Code unterscheidet.
Funktionsdeklaration: eine als separate Anweisung deklarierte Funktion im Hauptcodefluss:
// Funktionsdeklaration Funktion sum(a, b) { gib a + b zurück; }
Funktionsausdruck: eine Funktion, die innerhalb eines Ausdrucks oder innerhalb eines anderen Syntaxkonstrukts erstellt wird. Hier wird die Funktion auf der rechten Seite des „Zuweisungsausdrucks“ =
erstellt:
// Funktionsausdruck sei sum = function(a, b) { gib a + b zurück; };
Der subtilere Unterschied besteht darin, dass eine Funktion von der JavaScript-Engine erstellt wird.
Ein Funktionsausdruck wird erstellt, wenn die Ausführung ihn erreicht, und ist erst ab diesem Zeitpunkt verwendbar.
Sobald der Ausführungsfluss zur rechten Seite der Zuweisung übergeht, let sum = function…
– los geht's, die Funktion wird erstellt und kann von nun an verwendet (zugewiesen, aufgerufen usw.) werden.
Funktionsdeklarationen sind unterschiedlich.
Eine Funktionsdeklaration kann früher aufgerufen werden, als sie definiert ist.
Beispielsweise ist eine globale Funktionsdeklaration im gesamten Skript sichtbar, egal wo sie sich befindet.
Das liegt an internen Algorithmen. Wenn JavaScript die Ausführung des Skripts vorbereitet, sucht es zunächst darin nach globalen Funktionsdeklarationen und erstellt die Funktionen. Wir können es uns als eine „Initialisierungsphase“ vorstellen.
Und nachdem alle Funktionsdeklarationen verarbeitet wurden, wird der Code ausgeführt. Es hat also Zugriff auf diese Funktionen.
Das funktioniert zum Beispiel:
sayHi("John"); // Hallo, John Funktion sayHi(name) { alarm( `Hallo, ${name}` ); }
Die Funktionsdeklaration sayHi
wird erstellt, wenn JavaScript den Start des Skripts vorbereitet, und ist überall darin sichtbar.
…Wenn es ein Funktionsausdruck wäre, würde es nicht funktionieren:
sayHi("John"); // Fehler! let sayHi = function(name) { // (*) keine Magie mehr alarm( `Hallo, ${name}` ); };
Funktionsausdrücke werden erstellt, wenn die Ausführung sie erreicht. Das würde nur in der Zeile (*)
passieren. Zu spät.
Eine weitere Besonderheit von Funktionsdeklarationen ist ihr Blockumfang.
Wenn sich im strikten Modus eine Funktionsdeklaration innerhalb eines Codeblocks befindet, ist sie überall innerhalb dieses Blocks sichtbar. Aber nicht außerhalb davon.
Stellen wir uns zum Beispiel vor, dass wir abhängig von der age
, die wir zur Laufzeit erhalten, eine Funktion welcome()
deklarieren müssen. Und dann planen wir, es einige Zeit später zu verwenden.
Wenn wir die Funktionsdeklaration verwenden, funktioniert es nicht wie beabsichtigt:
let age = prompt("Wie alt sind Sie?", 18); // Eine Funktion bedingt deklarieren wenn (Alter < 18) { Funktion willkommen() { alarm("Hallo!"); } } anders { Funktion willkommen() { alarm("Grüße!"); } } // ...verwende es später Willkommen(); // Fehler: Willkommen ist nicht definiert
Das liegt daran, dass eine Funktionsdeklaration nur innerhalb des Codeblocks sichtbar ist, in dem sie sich befindet.
Hier ist ein weiteres Beispiel:
lass Alter = 16; // Nehmen Sie 16 als Beispiel wenn (Alter < 18) { Willkommen(); // (läuft) // | Funktion willkommen() { // | alarm("Hallo!"); // | Funktionsdeklaration ist verfügbar } // | überall im Block, wo es deklariert ist // | Willkommen(); // / (läuft) } anders { Funktion willkommen() { alarm("Grüße!"); } } // Hier haben wir keine geschweiften Klammern mehr, // Daher können wir darin keine Funktionsdeklarationen sehen. Willkommen(); // Fehler: Willkommen ist nicht definiert
Was können wir tun, um welcome
außerhalb von if
sichtbar zu machen?
Der richtige Ansatz wäre, einen Funktionsausdruck zu verwenden und der Variablen welcome
zuzuweisen, die außerhalb von if
deklariert wird und über die richtige Sichtbarkeit verfügt.
Dieser Code funktioniert wie vorgesehen:
let age = prompt("Wie alt sind Sie?", 18); willkommen heißen; wenn (Alter < 18) { willkommen = function() { alarm("Hallo!"); }; } anders { willkommen = function() { alarm("Grüße!"); }; } Willkommen(); // ok jetzt
Oder könnten wir es mit einem Fragezeichenoperator noch weiter vereinfachen ?
:
let age = prompt("Wie alt sind Sie?", 18); let willkommen = (Alter < 18) ? function() { alarm("Hallo!"); } : function() { Alert("Grüße!"); }; Willkommen(); // ok jetzt
Wann sollte man zwischen Funktionsdeklaration und Funktionsausdruck wählen?
Als Faustregel gilt: Wenn wir eine Funktion deklarieren müssen, müssen wir zunächst die Syntax der Funktionsdeklaration berücksichtigen. Es gibt mehr Freiheit bei der Organisation unseres Codes, da wir solche Funktionen aufrufen können, bevor sie deklariert werden.
Das ist auch besser für die Lesbarkeit, da es einfacher ist function f(…) {…}
im Code nachzuschlagen, als let f = function(…) {…};
. Funktionsdeklarationen sind „auffälliger“.
…Aber wenn uns eine Funktionsdeklaration aus irgendeinem Grund nicht zusagt oder wir eine bedingte Deklaration benötigen (wir haben gerade ein Beispiel gesehen), dann sollte ein Funktionsausdruck verwendet werden.
Funktionen sind Werte. Sie können an jeder Stelle des Codes zugewiesen, kopiert oder deklariert werden.
Wenn die Funktion als separate Anweisung im Hauptcodefluss deklariert wird, spricht man von einer „Funktionsdeklaration“.
Wenn die Funktion als Teil eines Ausdrucks erstellt wird, wird sie als „Funktionsausdruck“ bezeichnet.
Funktionsdeklarationen werden verarbeitet, bevor der Codeblock ausgeführt wird. Sie sind überall im Block sichtbar.
Funktionsausdrücke werden erstellt, wenn der Ausführungsfluss sie erreicht.
Wenn wir eine Funktion deklarieren müssen, ist in den meisten Fällen eine Funktionsdeklaration vorzuziehen, da diese vor der Deklaration selbst sichtbar ist. Das gibt uns mehr Flexibilität bei der Codeorganisation und ist in der Regel besser lesbar.
Daher sollten wir einen Funktionsausdruck nur verwenden, wenn eine Funktionsdeklaration für die Aufgabe nicht geeignet ist. Wir haben in diesem Kapitel einige Beispiele dafür gesehen und werden in Zukunft noch mehr sehen.