Funktionen — wiederverwendbare Codeblöcke
Ein weiteres essentielles Konzept im Coding sind Funktionen, die es Ihnen ermöglichen, ein Stück Code, der eine einzelne Aufgabe erfüllt, in einem definierten Block zu speichern. Dann können Sie diesen Code immer dann aufrufen, wenn Sie ihn benötigen, mit einem einzigen kurzen Befehl — anstatt denselben Code mehrmals eintippen zu müssen. In diesem Artikel werden wir grundlegende Konzepte hinter Funktionen untersuchen, wie grundlegende Syntax, wie man sie aufruft und definiert, Scope und Parameter.
| Voraussetzungen: | Ein Verständnis von HTML und den Grundlagen von CSS, Vertrautheit mit den JavaScript-Grundlagen, wie in den vorherigen Lektionen behandelt. |
|---|---|
| Lernziele: |
|
Wo finde ich Funktionen?
In JavaScript finden Sie Funktionen überall. In der Tat haben wir schon die ganze Zeit über Funktionen verwendet; wir haben nur nicht viel darüber gesprochen. Jetzt ist jedoch die Zeit gekommen, dass wir anfangen, explizit über Funktionen zu sprechen und ihre Syntax zu erforschen.
Fast immer, wenn Sie eine JavaScript-Struktur verwenden, die ein Paar Klammern — () — beinhaltet und nicht eine häufige eingebaute Sprachstruktur wie eine for-Schleife, while- oder do...while-Schleife, oder if...else-Anweisung verwenden, nutzen Sie eine Funktion.
Eingebaute Browser-Funktionen
Wir haben in diesem Kurs ausgiebig eingebaute Browser-Funktionen verwendet.
Jedes Mal, wenn wir einen Textstring manipuliert haben, zum Beispiel:
const myText = "I am a string";
const newString = myText.replace("string", "sausage");
console.log(newString);
// the replace() string function takes a source string,
// and a target string and replaces the source string,
// with the target string, and returns the newly formed string
Oder jedes Mal, wenn wir ein Array manipuliert haben:
const myArray = ["I", "love", "chocolate", "frogs"];
const madeAString = myArray.join(" ");
console.log(madeAString);
// the join() function takes an array, joins
// all the array items together into a single
// string, and returns this new string
Oder jedes Mal, wenn wir eine Zufallszahl generiert haben:
const myNumber = Math.random();
// the random() function generates a random number between
// 0 and up to but not including 1, and returns that number
Wir haben eine Funktion verwendet!
Hinweis: Fühlen Sie sich frei, diese Zeilen in die JavaScript-Konsole Ihres Browsers einzugeben, um sich mit deren Funktionalität neu vertraut zu machen, falls nötig.
Die JavaScript-Sprache hat viele eingebaute Funktionen, die es Ihnen ermöglichen, nützliche Dinge zu tun, ohne all diesen Code selbst schreiben zu müssen. Tatsächlich könnte ein Teil des Codes, den Sie aufrufen, wenn Sie eine eingebaute Browser-Funktion aufrufen (ein schickes Wort für Ausführen), nicht in JavaScript geschrieben werden — viele dieser Funktionen rufen Teile des Hintergrund-Codes des Browsers auf, der weitgehend in Systemsprachen wie C++ geschrieben ist, nicht in Websprache wie JavaScript.
Bedenken Sie, dass einige eingebaute Browser-Funktionen nicht Teil der JavaScript-Kernsprache sind — einige sind als Teil von Browser-APIs definiert, die auf der Standardsprache aufbauen, um noch mehr Funktionalität zu bieten (siehe diesen frühen Abschnitt unseres Kurses für weitere Beschreibungen). Wir werden die Verwendung von Browser-APIs in einem späteren Modul detaillierter betrachten.
Funktionen versus Methoden
Funktionen, die Teil von Objekten sind, werden als Methoden bezeichnet; Sie werden in einem späteren Modul über Objekte lernen. Für den Moment wollten wir nur potenzielle Verwirrung über die Begriffe Methode und Funktion klären — Sie werden wahrscheinlich beiden Begriffen begegnen, wenn Sie sich verwandte Ressourcen im Web ansehen.
Der eingebaute Code, den wir bisher verwendet haben, existiert in beiden Formen: Funktionen und Methoden. Sie können die vollständige Liste der eingebauten Funktionen sowie der eingebauten Objekte und ihrer entsprechenden Methoden in unserer JavaScript-Referenz einsehen.
Sie haben auch viele benutzerdefinierte Funktionen im Kurs gesehen — Funktionen, die in Ihrem Code definiert sind, nicht im Browser selbst. Jedes Mal, wenn Sie einen benutzerdefinierten Namen mit Klammern direkt danach gesehen haben, haben Sie eine benutzerdefinierte Funktion verwendet. In unserem random-canvas-circles.html Beispiel (siehe auch den vollständigen Quellcode) aus unserem Schleifen-Artikel haben wir eine benutzerdefinierte draw()-Funktion eingebaut, die so aussieht:
function draw() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
for (let i = 0; i < 100; i++) {
ctx.beginPath();
ctx.fillStyle = "rgb(255 0 0 / 50%)";
ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI);
ctx.fill();
}
}
Diese Funktion zeichnet 100 zufällige Kreise in ein <canvas> Element. Jedes Mal, wenn wir das machen wollen, können wir die Funktion mit folgendem Aufruf aufrufen:
draw();
anstatt jedes Mal den gesamten Code erneut eingeben zu müssen, wenn wir ihn wiederholen wollen. Funktionen können beliebigen Code enthalten — Sie können sogar andere Funktionen von innerhalb der Funktionen aufrufen. Die obige Funktion ruft zum Beispiel die random()-Funktion dreimal auf, die durch den folgenden Code definiert ist:
function random(number) {
return Math.floor(Math.random() * number);
}
Wir benötigten diese Funktion, weil die eingebaute Math.random()-Funktion des Browsers nur eine Zufallszahl zwischen 0 und 1 generiert. Wir wollten eine zufällige Ganzzahl zwischen 0 und einem angegebenen Wert.
Aufrufen von Funktionen
Sie sollten wahrscheinlich nun damit vertraut sein, aber nur für den Fall: Um tatsächlich eine Funktion zu nutzen, nachdem sie definiert wurde, müssen Sie sie ausführen — oder aufrufen. Dies wird erreicht, indem Sie den Namen der Funktion irgendwo im Code einfügen, gefolgt von Klammern.
function myFunction() {
alert("hello");
}
myFunction();
// calls the function once
Hinweis: Diese Form der Funktionsdefinition nennt man auch Funktionsdeklaration. Sie wird immer gehoben, sodass Sie die Funktion über der Funktionsdefinition aufrufen können und es funktioniert einwandfrei.
Funktionsparameter
Einige Funktionen erfordern die Angabe von Parametern, wenn Sie sie aufrufen — dies sind Werte, die in den Funktionsklammern enthalten sein müssen, damit die Funktion ihre Aufgabe ordnungsgemäß ausführen kann.
Hinweis: Parameter werden manchmal auch Argumente, Eigenschaften oder sogar Attribute genannt.
Zum Beispiel erfordert die eingebaute Math.random()-Funktion des Browsers keine Parameter. Wenn sie aufgerufen wird, gibt sie immer eine Zufallszahl zwischen 0 und 1 zurück:
const myNumber = Math.random();
Die eingebaute string replace()-Funktion des Browsers benötigt hingegen zwei Parameter — den zu findenden Teilstring im Hauptstring und den Teilstring, der diesen ersetzen soll:
const myText = "I am a string";
const newString = myText.replace("string", "sausage");
Hinweis: Wenn Sie mehrere Parameter angeben müssen, trennen Sie diese mit Kommata.
Optionale Parameter
Manchmal sind Parameter optional — Sie müssen sie nicht angeben. Wenn Sie dies nicht tun, übernimmt die Funktion im Allgemeinen ein Standardverhalten. Zum Beispiel ist der Parameter der array join()-Funktion optional:
const myArray = ["I", "love", "chocolate", "frogs"];
const madeAString = myArray.join(" ");
console.log(madeAString);
// returns 'I love chocolate frogs'
const madeAnotherString = myArray.join();
console.log(madeAnotherString);
// returns 'I,love,chocolate,frogs'
Wenn kein Parameter angegeben wird, um ein Verbindungs-/Trennzeichen zu spezifizieren, wird standardmäßig ein Komma verwendet.
Default-Parameter
Wenn Sie eine Funktion schreiben und optionale Parameter unterstützen wollen, können Sie Standardwerte angeben, indem Sie = nach dem Namen des Parameters hinzufügen, gefolgt vom Standardwert:
function hello(name = "Chris") {
console.log(`Hello ${name}!`);
}
hello("Ari"); // Hello Ari!
hello(); // Hello Chris!
Anonyme Funktionen und Pfeilfunktionen
Bisher haben wir Funktionen einfach so erstellt:
function myFunction() {
alert("hello");
}
Sie können aber auch eine Funktion erstellen, die keinen Namen hat:
(function () {
alert("hello");
});
Dies nennt man eine anonyme Funktion, weil sie keinen Namen hat. Anonyme Funktionen sehen Sie oft, wenn eine Funktion erwartet, eine andere Funktion als Parameter zu erhalten. In diesem Fall wird der Funktionsparameter oft als anonyme Funktion übergeben.
Hinweis: Diese Form der Funktionserstellung nennt man auch Funktionsausdruck. Im Gegensatz zu Funktionsdeklarationen werden Funktionsausdrücke nicht gehoben.
Beispiel für anonyme Funktionen
Angenommen, Sie möchten einen Code ausführen, wenn der Benutzer in ein Textfeld tippt. Dazu können Sie die Funktion addEventListener() des Textfeldes aufrufen. Diese Funktion erwartet mindestens zwei Parameter:
- Der Name des Ereignisses, auf das gehört werden soll, in diesem Fall
keydown - Eine Funktion, die ausgeführt wird, wenn das Ereignis eintritt.
Wenn der Benutzer eine Taste drückt, ruft der Browser die angegebene Funktion auf und übergibt ihr einen Parameter mit Informationen über das Ereignis, einschließlich der gedrückten Taste:
function logKey(event) {
console.log(`You pressed "${event.key}".`);
}
textBox.addEventListener("keydown", logKey);
Anstatt eine separate logKey()-Funktion zu definieren, können Sie eine anonyme Funktion in addEventListener() übergeben:
textBox.addEventListener("keydown", function (event) {
console.log(`You pressed "${event.key}".`);
});
Pfeilfunktionen
Wenn Sie eine anonyme Funktion auf diese Weise übergeben, gibt es eine alternative Form, die Sie verwenden können, die sogenannte Pfeilfunktion. Anstatt function(event), schreiben Sie (event) =>:
textBox.addEventListener("keydown", (event) => {
console.log(`You pressed "${event.key}".`);
});
Wenn die Funktion nur einen Parameter hat, können Sie die Klammern um den Parameter weglassen:
textBox.addEventListener("keydown", event => {
console.log(`You pressed "${event.key}".`);
});
Schließlich, wenn Ihre Funktion nur eine Zeile enthält, die ein return-Statement ist, können Sie auch die geschweiften Klammern und das return-Schlüsselwort weglassen und den Ausdruck implizit zurückgeben. Im folgenden Beispiel verwenden wir die map()-Methode von Array, um jeden Wert im ursprünglichen Array zu verdoppeln:
const originals = [1, 2, 3];
const doubled = originals.map(item => item * 2);
console.log(doubled); // [2, 4, 6]
Die map()-Methode übergibt jedes Element im Array an die gegebene Funktion, dann nimmt sie den von der Funktion zurückgegebenen Wert und fügt ihn einem neuen Array hinzu.
Die Pfeilfunktion ist sehr prägnant; Wenn wir unseren map()-Code umschreiben, um eine reguläre anonyme Callback-Funktion zu verwenden, würde das folgendermaßen aussehen:
const doubled = originals.map(function (item) {
return item * 2;
});
Sie können die gleiche prägnante Pfeilfunktions-Syntax verwenden, um das addEventListener()-Beispiel umzuschreiben:
textBox.addEventListener("keydown", (event) =>
console.log(`You pressed "${event.key}".`)
);
In diesem Fall wird der Wert von console.log(), der undefined ist, implizit aus der Callback-Funktion zurückgegeben.
Wir empfehlen die Verwendung von Pfeilfunktionen, da sie Ihren Code kürzer und lesbarer machen können. Um mehr zu erfahren, sehen Sie sich den Abschnitt über Pfeilfunktionen im JavaScript-Leitfaden an und unsere Referenzseite zu Pfeilfunktionen.
Hinweis: Es gibt einige subtile Unterschiede zwischen Pfeilfunktionen und normalen Funktionen. Sie liegen außerhalb des Umfangs dieses einführenden Tutorials und dürften in den hier besprochenen Fällen keinen Unterschied ausmachen. Um mehr zu erfahren, siehe die Referenzdokumentation zu Pfeilfunktionen.
Live-Beispiel für Pfeilfunktionen
Hier ist eine vollständige funktionierende Version des keydown-Beispiels, das wir oben besprochen haben:
Das HTML:
<input id="textBox" type="text" />
<div id="output"></div>
Das JavaScript:
const textBox = document.querySelector("#textBox");
const output = document.querySelector("#output");
textBox.addEventListener("keydown", (event) => {
output.textContent = `You pressed "${event.key}".`;
});
Das Ergebnis - versuchen Sie, in das Textfeld zu tippen und sehen Sie sich die Ausgabe an:
Funktions-Scope und Konflikte
Lassen Sie uns über Scope sprechen — ein wichtiges Konzept im Umgang mit Funktionen. Wenn Sie eine Funktion erstellen, sind die Variablen und andere Dinge, die innerhalb der Funktion definiert sind, in ihrem eigenen separaten Scope. Das bedeutet, dass sie in ihrer eigenen separaten Abteilung eingeschlossen sind und von Code außerhalb der Funktion nicht erreicht werden können.
Die oberste Ebene außerhalb aller Ihrer Funktionen wird als globaler Scope bezeichnet. Werte, die im globalen Scope definiert sind, sind von überall im Code aus zugänglich.
JavaScript funktioniert hauptsächlich aus Sicherheits- und Organisationsgründen so. Manchmal möchten Sie nicht, dass Variablen von überall im Code aus zugänglich sind. Externe Skripte, die von anderen Orten aufgerufen werden, könnten anfangen, in Ihren Code einzugreifen und Probleme verursachen, wenn sie dieselben Variablennamen verwenden und Konflikte entstehen. Dies könnte absichtlich oder einfach aus Versehen geschehen.
Zum Beispiel, wenn Sie eine HTML-Datei haben, die auf zwei externe JavaScript-Dateien verweist, und beide haben eine Variable und eine Funktion definiert, die denselben Namen verwenden:
<!-- Excerpt from the HTML -->
<script src="first.js"></script>
<script src="second.js"></script>
<script>
greeting();
</script>
// first.js
const name = "Chris";
function greeting() {
alert(`Hello ${name}: welcome to our company.`);
}
// second.js
const name = "Zaptec";
function greeting() {
alert(`Our company is called ${name}.`);
}
Sie können dieses Beispiel live auf GitHub ausführen (siehe auch den Quellcode). Laden Sie es in einem separaten Browser-Tab, bevor Sie die untenstehende Erklärung lesen.
-
Wenn das Beispiel in einem Browser geladen wird, sehen Sie zuerst ein Warnfenster mit der Anzeige
Hello Chris: welcome to our company., was bedeutet, dass diegreeting()-Funktion, die im ersten Skriptdatei definiert ist, durch dengreeting()-Aufruf im internen Skript aufgerufen wurde. -
Das zweite Skript jedoch wird überhaupt nicht geladen und ausgeführt, und eine Fehlermeldung wird in der Konsole gedruckt:
Uncaught SyntaxError: Identifier 'name' has already been declared. Dies liegt daran, dass diename-Konstante bereits infirst.jsdeklariert wurde, und Sie können dieselbe Konstante nicht zweimal im selben Scope deklarieren. Da das zweite Skript nicht geladen wurde, ist diegreeting()-Funktion aussecond.jsnicht verfügbar, um aufgerufen zu werden. -
Wenn wir die Zeile
const name = "Zaptec";aussecond.jsentfernen und die Seite neu laden würden, würden beide Skripte ausgeführt. Das Warnfenster würde nunOur company is called Chris.anzeigen. Wenn eine Funktion neu deklariert wird, wird die letzte Deklaration in der Quellreihenfolge verwendet. Die vorherigen Deklarationen werden effektiv überschrieben.
Das Einsperren von Teilen Ihres Codes in Funktionen vermeidet solche Probleme und wird als beste Praxis angesehen.
Es ist ein bisschen wie in einem Zoo. Die Löwen, Zebras, Tiger und Pinguine werden in ihren eigenen Gehegen gehalten und haben nur Zugang zu den Dingen im Inneren, ähnlich wie bei Funktions-Scopes. Wenn sie in andere Gehege gelangen könnten, würden Probleme entstehen. Im besten Fall würden sich verschiedene Tiere in fremden Lebensräumen wirklich unwohl fühlen — ein Löwe oder Tiger würde sich in der wässrigen, eisigen Umgebung der Pinguine schrecklich fühlen. Im schlimmsten Fall könnten die Löwen und Tiger versuchen, die Pinguine zu fressen!

Der Zoodirektor ist wie der globale Scope — er hat die Schlüssel, um jedes Gehege zu betreten, Lebensmittel aufzufüllen, kranke Tiere zu pflegen usw.
Spielen mit Scope
Schauen wir uns ein echtes Beispiel an, um den Scope zu demonstrieren.
-
Erstellen Sie zunächst eine lokale Kopie unseres function-scope.html Beispiels. Dieses enthält zwei Funktionen namens
a()undb(), und drei Variablen —x,yundz— von denen zwei innerhalb der Funktionen definiert sind und eine im globalen Scope. Es enthält auch eine dritte Funktion namensoutput(), die einen einzelnen Parameter nimmt und ihn in einem Absatz auf der Seite ausgibt. -
Öffnen Sie das Beispiel in einem Browser und in Ihrem Texteditor.
-
Öffnen Sie die JavaScript-Konsole in Ihren Browserentwicklertools. Geben Sie in der JavaScript-Konsole den folgenden Befehl ein:
jsoutput(x);Sie sollten den Wert der Variablen
xim Browserfenster angezeigt sehen. -
Versuchen Sie nun, Folgendes in Ihrer Konsole einzugeben
jsoutput(y); output(z);Beide sollten einen Fehler in die Konsole werfen, ähnlich wie "ReferenceError: y is not defined". Warum ist das so? Wegen des Funktions-Scopes:
yundzsind in dena()- undb()-Funktionen eingeschlossen, sodassoutput()nicht auf sie zugreifen kann, wenn es aus dem globalen Scope aufgerufen wird. -
Was aber, wenn es von innerhalb einer anderen Funktion aufgerufen wird? Versuchen Sie,
a()undb()so zu bearbeiten, dass sie so aussehen:jsfunction a() { const y = 2; output(y); } function b() { const z = 3; output(z); }Speichern Sie den Code und laden Sie ihn im Browser neu, dann versuchen Sie, die
a()undb()Funktionen von der JavaScript-Konsole aus aufzurufen:jsa(); b();Sie sollten die
yundzWerte im Browserfenster angezeigt sehen. Dies funktioniert einwandfrei, weil dieoutput()-Funktion innerhalb der anderen Funktionen aufgerufen wird, im selben Scope, in dem die Variablen, die sie ausgibt, definiert sind.output()selbst ist von überall aus verfügbar, da es im globalen Scope definiert ist. -
Versuchen Sie nun, Ihren Code so zu aktualisieren:
jsfunction a() { const y = 2; output(x); } function b() { const z = 3; output(x); } -
Speichern und laden Sie erneut, und versuchen Sie es erneut in Ihrer JavaScript-Konsole:
jsa(); b();Sowohl die
a()als auch dieb()Aufrufe sollten den x-Wert im Browserfenster ausgeben. Diese Aufrufe funktionieren einwandfrei, weil, obwohl dieoutput()-Aufrufe nicht im selben Scope wiexdefiniert sind,xeine globale Variable ist — es ist in allen Codes überall verfügbar. -
Versuchen Sie schließlich, Ihren Code so zu aktualisieren:
jsfunction a() { const y = 2; output(z); } function b() { const z = 3; output(y); } -
Speichern und laden Sie erneut, und versuchen Sie es erneut in Ihrer JavaScript-Konsole:
jsa(); b();Diesmal werfen die
a()undb()Aufrufe den ärgerlichen ReferenceError: variable name is not defined Fehler in die Konsole — das liegt daran, dass dieoutput()-Aufrufe und die Variablen, die sie zu drucken versuchen, nicht im selben Funktions-Scope liegen — die Variablen sind für diese Funktionsaufrufe effektiv unsichtbar.
Hinweis: Der ReferenceError: "x" is not defined Fehler ist einer der häufigsten, auf die Sie stoßen werden. Wenn Sie diesen Fehler erhalten und sicher sind, dass Sie die Variable in Frage definiert haben, überprüfen Sie, in welchem Scope sie sich befindet.
Eine Randbemerkung zu Schleifen- und bedingtem Scope
Es ist bemerkenswert, dass der Scope von Werten, die innerhalb von Bedingungen und Schleifen deklariert wurden, genauso funktioniert wie der Funktionsscope beim Deklarieren von Werten mit let und const. Wenn Sie zum Beispiel die folgenden Blöcke zum obigen Beispiel hinzufügen:
if (x === 1) {
const c = 4;
let d = 5;
}
for (let i = 0; i <= 1; i++) {
const e = 6;
let f = 7;
}
Der Aufruf von output(c), output(d), output(e), oder output(f) würde den gleichen "ReferenceError: [variable-name] is not defined" Fehler ergeben, den wir bereits gesehen haben. Die output()-Funktion hat keinen Zugriff auf diese Variablen, da sie in ihrem eigenen Scope eingeschlossen sind.
Das alte var-Schlüsselwort funktioniert anders. Wenn c, d, e, und f mit var deklariert wurden:
if (x === 1) {
var c = 4;
var d = 5;
}
for (let i = 0; i <= 1; i++) {
var e = 6;
var f = 7;
}
würden sie in den globalen Scope gehoben werden; daher würde das Ausgeben von ihnen in die Konsole (zum Beispiel mit output(c)) funktionieren. Mit var deklarierte Variablen innerhalb von Funktionen haben jedoch weiterhin ihren Scope auf diese Funktionen beschränkt.
Diese Inkonsistenz kann Verwirrung und Fehler verursachen, und ist ein weiterer Grund, warum Sie let und const anstelle von var verwenden sollten.
Zusammenfassung
In diesem Artikel haben wir die grundlegenden Konzepte hinter Funktionen erforscht und damit den Weg für den nächsten Artikel geebnet, in dem wir Sie durch die Schritte zur Erstellung Ihrer eigenen benutzerdefinierten Funktion führen.
Siehe auch
- Detaillierter Leitfaden zu Funktionen — behandelt einige fortgeschrittene Funktionen, die hier nicht enthalten sind.
- Funktionsreferenz
- Funktionen verwenden, um weniger Code zu schreiben, Scrimba MDN Lernpartner - Eine interaktive Lektion, die eine nützliche Einführung in Funktionen bietet.