JavaScript/Tutorials/Einstieg/Funktionen

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Wenn die Programme länger und komplexer werden, macht eine klare Programmstruktur die Fehlersuche deutlich einfacher.

In diesem Kapitel lernen Sie, wie Sie monolithische Konstruktionen mit unübersichtlichem Spaghetticode vermeiden und die verschiedenen Aufgaben Ihres Programms stattdessen auf relativ kurze und gut überschaubare Unterprogramme (in JavaScript Funktionen genannt) gliedern, wobei dann auch nicht mit Kommentaren gespart werden sollte.

Funktionen

Funktionen helfen Programmierern, einzelnen Programmteilen einen Namen zu geben und diese mehrfach wiederzuverwenden.

Das Grundprinzip ist leicht:

  1. Das gesamte Programm wird in einzelne Aufgaben zerlegt.
  2. Die einzelnen Schritte dieser Aufgabe werden in einer Funktion notiert.
  3. Diese Funktion wird aufgerufen. Dabei kann sie unterschiedliche Parameter enthalten. Die Funktion erfüllt anhand der Parameter eine bestimmte Aufgabe und gibt das Ergebnis zurück. Je nach Parameter wird die Funktion üblicherweise auch andere Resultate liefern.
Aufbau einer Funktion
function funktionsname(Parameterliste) {
  // Anweisungen
}

Jede Funktion hat einen Namen, eine Parameterliste und einen Rückgabewert. Die Parameter sind Eingabewerte für die Funktion. Sie stehen innerhalb der Funktion als Variablen zur Verfügung. Das heißt, dass man über die Parameter Daten in die Funktion hineingibt, in der Funktion dann verarbeitet und das Verarbeitungsergebnis dann über den Rückgabewert an den Aufrufer der Funktion zurückgibt.

Mit dem Schlüsselwort return kann das Ende des Funktionsaufrufes eingeleitet werden. Steht nach diesem Schlüsselwort noch ein Ausdruck (z.B. ein Variablenname), wird das Ergebnis dessen Auswertung als Rückgabewert an den Aufrufer der Funktion zurück gegeben.
Steht am Ende der Funktion kein return, oder folgt auf das Schlüsselwort kein Ausdruck, wird der Wert undefined zurückgegeben.

Beachten Sie: Die folgenden Beispiele verwenden der Einfachheit wegen zwei Funktionen (alert() und prompt()), die für echte Anwendungsfälle auf Webseiten ernste Nachteile haben. Wie man diese vermeidet, beschreibt ein Kapitel für Fortgeschrittene: JavaScript/Tutorials/Eigene_modale_Dialogfenster

Betrachten wir hierzu ein Beispiel, das Ziehen der Quadratwurzel:

9. Funktion WurzelZiehen ansehen …
  'use strict';
  let
    eingabe,
    ergebnis,
    text;

  // Hilfsfunktion, die Wurzel aus übergebener 'zahl' zieht und als 'ergebnis' zurückgibt
  function wurzelZiehen(zahl) {
    let wurzel;
    zahl = parseFloat(zahl);
    wurzel = Math.sqrt(zahl);
    return wurzel;
  }

  eingabe = prompt('Bitte geben Sie eine Zahl ein!');

  ergebnis = wurzelZiehen(eingabe);
  text = `Die Wurzel von ${eingabe} ist ${ergebnis}.`;
  alert(text);

Nachdem die Variablen deklariert wurden, wird eine Funktion wurzelZiehen() erzeugt, aber nicht ausgeführt.

Die geschweiften Klammern kennzeichnen Start und Ende des Anweisungsblocks.
Damit bei einer Eingabe eines Buchstabens oder ähnlichem keine Fehlermeldung NaN ausgeworfen wird, wird die übergebene Variable überprüft und, wenn nötig mit parseFloat passend formatiert.

Die Funktion zieht mit Math.sqrt() die Wurzel aus der übergebenen Zahl und weist sie der Variablen wurzel zu. Der Rückgabewert der Funktion ist die Variable wurzel und wird durch das Schlüsselwort return gekennzeichnet. Mit diesem Befehl wird die Funktion also beendet und gleichzeitig der Inhalt von wurzel an den Aufrufer von wurzelZiehen zurückgegeben.

Wenn eine Ziffernfolge als Wert für eingabe eingegeben wird, wird die Funktion wurzelZiehen(eingabe) aufgerufen und ihr die Variable eingabe übergeben. Der Rückgabewert wird in der Variablen ergebnis abgelegt. Dieses wird dann in den Ausgabetext eingefügt und für den Benutzer sichtbar ausgegeben.


Beachten Sie: Die Überprüfung der Eingabe mit parseFloat sollte schon bei der Eingabe erfolgen, sodass an die Funktion wurzelZiehen nur gültige Zahlen übergeben werden. Aus Gründen der Einfachheit wurde hier darauf verzichtet.
Wenn eine Webseite Formulare mit passenden Eingabefeldern verwendet, kann durch die Verwendung von input type="number" sichergestellt werden, dass nur Zahlen eingegeben werden können.

Wie Sie sicherlich gesehen haben, entstehen beim Wurzelziehen nur in den seltensten Fällen ganze Zahlen. Da die Dezimalzahlen nicht besonders ansehnlich sind, können Sie sie auch runden:

10. Runden einer Zahl ansehen …
'use strict';
  let eingabe,
      ergebnis,
      gerundet,
      text;

  //Helferfunktionen
  function wurzelZiehen(zahl) {
    let wurzel = Math.sqrt(zahl);
    return wurzel;
  }

  function runden(zahl) {
    let rund = zahl.toFixed(2);
    return rund;
  }

  eingabe = prompt('Bitte geben Sie eine Zahl ein!');

  if (isNaN(eingabe)) {
    alert(`Der eingebenene Wert ${eingabe} ist keine Zahl!`);
  }

  eingabe = parseFloat(eingabe);
  ergebnis = wurzelZiehen(eingabe);
  gerundet = runden(ergebnis);
  text = `Die Wurzel von ${eingabe} ist ${ergebnis}, gerundet: ${gerundet}.`;
  alert(text);

Direkt nach der Eingabe wird der erhaltene Wert überprüft und, wenn nötig mit parseFloat passend formatiert.

In einer Abfrage wird überprüft, ob die Variable eingabe einen ungültigen Zahlenwert enthält. Wenn das der Fall ist, wird eine passende Fehlermeldung mit alert() ausgegeben.

Die Funktion wurzelZiehen() berechnet die Wurzel von zahl, wobei sie sich darauf verlässt, dass in dieser Variable ein gültiger Zahlenwert steht. Im Vergleich zu unserem vorherigen Beispiel sorgt hier der Programmverlauf dafür, dass das auch so ist. Das Ergebnis wird in die Variable wurzel geschrieben und deren Wert an den Aufrufer zurückgegeben. Der Aufrufer speichert diesen Wert in der Variable ergebnis.

Die Funktion runden() verwendet toFixed(2), um die Dezimalzahl in zahl auf eine bestimmte Anzahl Nachkommastellen zu runden. Dem Aufruf von toFixed() wird die Zahl 2 mitgegeben, womit die Dezimalzahl auf zwei Nachkommastellen gerundet wird. Das Ergebnis von toFixed() wird in der Variable rund gespeichert und anschließend an den Aufrufer zurückgegeben, welcher den gerundeten Wert in der Variable gerundet speichert.

Anschließend werden sowohl das genaue Ergebnis als auch die gerundete Zahl ausgegeben.


Empfehlung:
Programmieren Sie Funktionen so allgemein wie möglich, damit Sie sie mehrfach und unter möglichst verschiedenen Bedingungen einsetzen können.

Vorteile einer solchen Programmierung nach dem Grundsatz DRY (Don't repeat yourself!) sind:

  • kürzere Programme
  • bessere Lesbarkeit von Programmcode
  • ein besser zu wartender Code bei künftigen Überarbeitungen

Im Laufe der Zeit sammelt sich so eine Bibliothek an wiederverwendbaren Helfer-Funktionen, die Ihnen viel Arbeit sparen.

Funktionen, die einem Objekt gehören: Methoden

Objekte sind nicht nur ein Behälter für Eigenschaftsnamen und ihre Werte, sie können auch Funktionen besitzen, die im Zusammenhang dieses Objektes definiert sind. Man spricht dann von Methoden:

eigenes Objekt in JavaScript
const Person = {
  name: 'Anna',
  alter: 31,
  gibAuskunft: function () {
    return `Ich heiße ${this.name} und bin ${this.alter} Jahre alt.`;
  }
};

Person.gibAuskunft(); // Ich heiße Anna und bin 31 Jahre alt.

Person.name = 'Anna-Maria';
Person.alter = 25;

Person.gibAuskunft(); // Ich heiße Anna-Maria und bin 25 Jahre alt.

Die Eigenschaft gibAuskunft ist eine Funktion, die im Kontext des Objektes steht und deshalb mit dem Schlüsselwort this auf die Eigenschaften des Objekts zugreifen kann. Das macht es möglich, dass die Platzhalter (wie z.B. ${this.name}) entsprechend befüllt werden können.

Die Bindung der Funktion an das Objekt hat den Vorteil, dass sie sich nur für die Eigenschaften von diesem Objekt interessiert. Sie braucht in diesem Beispiel auch keine weiteren Parameter beim Aufruf, weil sie sich alle Daten aus ihrer Objektzugehörigkeit ableiten kann, um die Werte für alter und name zu ermitteln.

Alles ist ein Objekt

Die Sprache JavaScript wurde mit der Maxime entworfen, dass alles darin ein Objekt sein soll. Das bedeutet, dass auch primitive Datentypen in Wirklichkeit Objekte sind, die mehr können, als nur ihren Wert speichern. Hier zwei Beispiele, die zeigen sollen, dass in Wirklichkeit echte Objekte im Hintergrund stehen:

Alles ist ein Objekt
let a = 'SELFHTML', b = 25;
a.substr(3,3); // FHT
b.toFixed(2); // 25.00

In der Variable a wird eine Zeichenkette gespeichert, in der Variable b die Zahl 25.
Die erste Ausgabe auf die Browserkonsole soll nun einen Teil der Zeichenkette enthalten, und zwar beginnend ab dem vierten Zeichen (wir fangen bei null zu zählen an!), drei Zeichen lang. Damit das gelingt, wird eine Methode des Zeichenketten-Objektes verwendet, genauer des String-Objektes, die substr()-Methode. Bei dem Wert der Variable a handelt es sich also nicht nur um eine Zeichenkette, sondern um ein String-Objekt.
Die zweite Ausgabe auf die Browserkonsole soll eine Dezimalzahl mit zwei Stellen enthalten. Damit das gelingt, wird eine Methode des Zahl-Objektes verwendet, genauer des Number-Objektes, die toFixed()-Methode. Bei dem Wert der Variable b handelt es sich also nicht nur um eine Zahl, sondern um ein Number-Objekt.

Funktionen sind also auch ein Objekt?

Wenn in JavaScript alles ein Objekt sein soll, dann gibt es auch Funktionsobjekte. Das wird deutlich, wenn man einer Variablen eine Funktion als Wert zuweist:

Funktion einer Variable zuweisen
const f = function (x) { return x * 2 + 3; };
f(3);  // 9
f(19); // 41

Der Variable f wird ein Funktionsobjekt zugewiesen, welches als Literal ausnotiert im Code steht. Dieses Funktionsobjekt kann nun mit dem Namen der Variable, also f, aufgerufen werden, was die beiden Ausgaben auf die Browserkonsole zeigen.

Man kann Funktionen auch als Wert in einem Funktionsaufruf an eine andere Funktion geben. Das macht man sich insbesondere dann zunutze, wenn man bei bestimmten Browserereignissen (z.B. Eingaben mit Maus oder Tastatur) entsprechend reagieren möchte. In solchen Fällen übergibt man ein Funktionsobjekt als Parameter an eine andere Funktion, die dafür sorgt, dass in solchen Fällen diese Funktion abgearbeitet wird.