JavaScript: Funktionen

Einführung

Mit Funktionen können Sie flexible Teilprogramme notieren.

... Das haben Sie sicher schon im Grundlagenkurs Programmierung gelernt, oder kennen es schon von anderen Programmiersprachen. ...

Die vorgegebenen JavaScript-Objekte bieten in erster Linie Funktionen, die Sie in Ihren Scripten aufrufen können.

In JavaScript spielen Funktionen einen höheren Stellenwert als in anderen Programmiersprachen und haben einige Besonderheiten - deshalb spricht man davon, dass JavaScript Aspekte einer funktionalen Programmiersprache besitzt. In JavaScript sind Funktionen nicht einfach feste, einmal definierte Script-Bestandteile, sondern selbst Objekte, mit denen man im Script nahezu ungehindert arbeiten kann. Sie können sogar problemlos neue Funktionen zur Laufzeit erzeugen und einmal definierte wieder löschen.

Wenn Sie eigene Funktionen definieren, so können Sie sie an bestimmte andere Objekte hängen. Das bedeutet, sie als Unterobjekte eines Objektes zu speichern. In diesem Fall spricht man in der Terminologie der objektorientierten Programmierung von einer Methode. In anderen Fällen ist es sinnvoller, die Funktion als lokale Variable in einer anderen Funktion anzulegen. Und schließlich brauchen Sie die Funktion gar nicht zu speichern - sie können Sie auch anonym (namenlos) anlegen, nur um sie z.B. als Parameter an eine andere Funktion weiterzugeben. Diese drei Möglichkeiten werden Ihnen später noch klarer werden, wenn wir betrachten, auf welche Weise Sie Funktionen erzeugen können.

Funktionsdeklarationen

Es gibt drei Arten, wie Sie Funktionen notieren und damit Funktionsobjekte erzeugen können. Die einfachste und wichtigste Art ist die sogenannte Funktions-Deklaration (auf englisch function declaration). Deren Syntax ist folgendermaßen aufgebaut:

function Funktionsname (Parameterliste) {
Anweisungen
}

Der Funktionsname muss den üblichen Anforderungen an JavaScript-Bezeichner genügen: Sie dürfen Buchstaben, Zahlen und einige Sonderzeichen (das Dollar-Zeichen, den Unterstrich ... TODO) verwenden. Der Funktionsname darf in diesem Fall aber keine Leerzeichen enthalten. TODO: Wann darf er das?

Die Parameterliste zwischen den beiden runden Klammern ist eine durch Kommas getrennte Liste von Namen. Für diese gelten die besagten Namenskonventionen. Unter den in dieser Auflistung vergebenen Namen können Sie innerhalb der Funktion auf die übergebenen Parameter zugreifen.

Zwischen den beiden geschweiften Klammern wird der sogenannte Funktionskörper notiert: Darin werden die Anweisungen untergebracht, die beim Aufruf der Funktion ausgeführt werden sollen.

Folgendes Beispiel soll das Schema verdeutlichen:

function statusMeldung (meldungsTyp, meldungsText) {
var ausgabeElement = document.getElementById("meldungsausgabe");
ausgabeElement.className = meldungsTyp;
ausgabeElement.innerHTML = meldungsText;
}
statusMeldung("fehler", "Beim Absenden Ihrer Nachricht ist ein Fehler aufgetreten. " +
"Bitte versuchen Sie es erneut."); 

Das Beispiel definiert eine Funktion mit dem Namen statusMeldung. Die Funktion erwartet zwei Parameter mit dem Namen meldungsTyp bzw. meldungsText.

Die Funktion wird nach dem Schema Funktionsname(Parameterliste) aufgerufen. Die beiden runden Klammern nach dem Funktionsnamen sind der eigentliche

...

Was passiert: wenn Sie direkt in einem script-Element notieren, wird eine globale Funktion angelegt. Das ist eine Methode des window-Objektes ... Globale Variablen sind wiederum nichts anderes als Eigenschaften des Objektes window.

bla() = window.bla()! window["bla"]!

Funktionsparameter

Bei der Deklaration weisen Sie den Funktionsparametern

function Summe (zahl1, zahl2, zahl3) {

}

Summe(5, 10, 15);

Variable Parameterzahl: Der arguments-Array

Rückgabewert (Ergebnis)

return

Lokale Variablen (Funktionsvariablen)

Gültigkeitsbereich (Scope)

Funktionsausdrücke

Wie gesagt gibt es neben der oben vorgestellten zwei weitere, also insgesamt drei Schreibweisen, mit denen Sie Funktionen erzeugen können. Je nach Verwendungszweck können die folgenden weniger bekannten Schreibweisen passender sein.

Die zweite Art, wie Sie Funktionen notieren können, ist der sogenannte Funktions-Ausdruck (englisch function expression). Diese Schreibweise hat viele Vorteile, Sie werden sie schätzen lernen und vielfältig anwenden können.

Um den Unterschied zwischen Funktionsdeklaration und Funktionsausdruck zu verstehen, müssen Sie den Unterschied zwischen Anweisungen (Statements) und Ausdrücken (Expressions) kennen. Die vorgestellte Funktionsdeklaration ist nämlich eine Anweisung, der Funktionsausdruck hingegen ein Ausdruck. Damit haben beide unterschiedliche Anwendungsmöglichkeiten. Sie können Funktionsausdrücke an viel mehr Stellen notieren als eine Funktionsdeklaration.

Das Schema eines Funktionsausdruckes sieht folgendermaßen aus:

function (Parameterliste) { Anweisungen }

Ein solcher Funktionsausdruck selbst ergibt lediglich eine Funktion, speichert Sie aber nicht unter einem Namen. Man spricht daher auch von anonymen (namenlosen) Funktionen.

Das Ergebnis des Ausdruckes, ein Funktionsobjekt, können Sie jedoch weiterverwenden. Beispielsweise können Sie das erzeugte Funktionsobjekt in einer Variable speichern:

var Funktionsname = function (Parameterliste) { Anweisungen };

Dieses Variablenzuweisung mit Funktionsausdruck hat denselben Effekt wie die klassische Funktionsdeklaration function Funktionsname (...) {...}. Das bedeutet, sie sind unter allen Umständen austauschbar.

Darüber lässt sich auch genauer verstehen, was eine Funktionsdeklaration macht. Wenn die gleichwertigen Anweisungen innerhalb einer Funktion notiert werden, wird eine lokale Variable erzeugt, in der die neue Funktion gespeichert wird. Stehen sie außerhalb einer Funktion ausgeführt, dann wird eine globale Variable erzeugt, das heißt die neue Funktion wird als Methode von Objektes window angelegt.

Was sind nun die Vorteile eines Funktionsausdruckes?

Mit Funktionsdeklarationen erzeugt man üblicherweise globale Funktionen (window-Methoden). Wenn Sie eine Funktion mittels Funktionsausdruck erzeugen, müssen Sie diese nicht zwangsläufig global als window-Methode abspeichern, sondern können sie auch an einem anderen Objekt speichern. Auf diese Weise können Sie Ordnung in Ihre Scripte bringen und zusammenhörige Variablen z.B. unter einem Objekt gruppieren. Ein Beispiel:

var bildergalerie = new Object();
bildergalerie.abspielen = function () {
/* ... */
};
bildergalerie.abspielen();

Im obigen Beispiel wird eine leere Object-Instanz erzeugt, die als globale Variable mit dem Namen bildergalerie gespeichert wird. In der zweiten Zeile wird dem zunächst leeren Objekt eine Methode hinzugefügt. Die entsprechende Funktion wird mithilfe eines Funktionsausdrucks notiert. Das entstehende Funktionsobjekt wird in der Eigenschaft abspielen gespeichert (siehe Object-Objekte als Zuordnungslisten). In der dritten Zeile schließlich wird diese Funktion aufgerufen.

Die Gruppierung unter dem Objekt bildergalerie hat den Vorteil, dass der globale Gültigkeitsbereich, das window-Objekt, nicht übermäßig mit eigenen Objekten beschrieben wird. Der Verzicht auf globale Variablen hat den Vorteil, dass mehrere Scripte problemlos zusammenarbeiten können. [TODO: Diese Programmiertechnik der Kapselung zentral beschreiben.]

Im Beispiel wird lediglich das Objekt bildergalerie global gespeichert, das heißt als Eigenschaft von window. Folglich darf an keiner anderen Stelle eine gleichnamige globale Variable erzeugt werden, sonst würde das Objekt überschrieben werden. Die Funktion abspielen hängt hingegen als Methode am bildergalerie-Objekt. Sie kann anderen, gleichnamigen Funktionen nicht in die Quere kommen.

...

Eine weitere häufige Anwendung von Funktionsausdrücken findet sich im Event-Handling. Um eine Handler-Funktionen zu notieren, können Sie herkömmliche Funktionsdeklarationen nutzen:

// Handler-Funktion mit Funktionsdeklaration notieren
function init () {
window.alert("Dokument ist fertig geladen!");
}
// Event-Handler registrieren
window.onload = init;

Im Beispiel wird eine globale Funktion namens init angelegt und daraufhin als Event-Handler für das load-Ereignis beim window-Objekt registriert (siehe traditionelles Event-Handling).

Diese Schreibweise ergibt Sinn, wenn Sie die Funktion init später noch einmal benötigen. Üblicherweise ist das nicht der Fall: Man braucht solche Funktionen nur an der Stelle, wo man sie als Handler registriert; es ist nicht nötig, sie irgendwo unter einem Namen zu speichern.

In diesem Fall kann ein Funktionsausdruck den Code vereinfachen. Notieren Sie die Handler-Funktion mit einem Ausdruck und speichern Sie sie direkt in der onload-Eigenschaft:

window.onload = function () {
window.alert("Dokument ist fertig geladen!");
};

Dasselbe Prinzip können Sie überall beim Event-Handling anwenden. Wenn Sie beispielsweise einem Element einen click-Handler zuweisen wollen, so könnten Sie die fragliche Funktion mit einer Deklaration notieren:

function klickHandler () {
window.alert("Element wurde geklickt!");
}
document.getElementById("bla").onclick = klickHandler;

Üblicherweise besteht keine Notwendigkeit, die Handler-Funktion global unter dem Namen »klickHandler« zu speichern. Stattdessen können Sie einen Funktionsausdruck verwenden und die erzeugte Funktion direkt als click-Handler abspeichern:

document.getElementById("bla").onclick = function () {
window.alert("Element wurde geklickt!");
};

Es gibt noch viele weitere Fälle, in denen das Zwischenspeichern einer Funktion, wie es eine Funktionsdeklaration zwangsläufig tut, unnötig ist - und damit gibt es es zahlreiche weitere Anwendungsmöglichkeiten für Funktionsausdrücke. Im Abschnitt über Closures werden wir darauf zurückkommen.

Function-Konstruktor

Wenden wir uns der dritten und letzten Möglichkeit zur Erzeugung von Funktionen zu. Dieser brauchen Sie keine große Aufmerksamkeit schenken, denn ihr Anwendungsbereich ist klein und ihr Gebrauch entsprechend selten.

Alle Funktionen, egal wie sie erzeugt wurden, sind Instanzen des Function-Konstruktors. Sie können daher auch direkt diesen Konstruktor aufrufen, um eine weitere Instanz zu erzeugen. Die Schreibweise lautet folgendermaßen:

new Function("Anweisungen", "Parametername1", "Parametername2", ...)

Sie rufen Function mit dem Schlüsselwort new auf. Der Konstruktor erwartet die Anweisungen, d.h. den Funktionskörper, im ersten Parameter. Dabei muss es sich um einen String handeln! Der zweite, dritte und alle folgenden Parameter enthalten die Parameternamen der neuen Funktion - ebenfalls als Strings. Wenn die zu erzeugende Funktion drei Parameter namens ...

Der Aufruf von new Function(...) erzeugt lediglich eine Funktion, speichert sie selbst aber noch nicht. Sie kennen das bereits vom Funktionsausdruck. Möchten Sie die erzeugte Funktion in einer lokalen Variable speichern, können Sie notieren:

var quadrat = new Function(
// Funktionskörper mit Anweisungen
"window.alert('Das Quadrat der Zahl ' + zahl + 'lautet: ' + (zahl * zahl);",
// Name des ersten Parameters
"zahl"
);
// Aufruf der erzeugten Funktion
quadrat(5);

Diese recht umständliche Notationsweise macht nur dann Sinn, wenn Sie in Ihrem JavaScript-Programm JavaScript-Code als String gespeichert haben und eine Funktion daraus machen wollen. Dies kommt freilich nur in einigen Spezialanwendungen vor.

Verwenden Sie nach Möglichkeit die beschriebenen Funktionsdeklarationen und -ausdrücke.

Verschachtelte Funktionen (Closures)

Fortgesch

siehe Artikel


function meineFunktion () {
document.getElementBy
}
window.setTimeout(meineFunktion, 5000);

function irgendeineFunktion () {
var bla = "string"; // diese Variable ist nur in dieser Funktion verfügbar
var status = 50;
setTimeout(
  function () {
	 // Verschachtelte Funktion
	 // Closure!
	 alert(status);
  },
  5000
);
}

Funktionale Programmierg: Funktionen als Objekte verwenden

Funktionen sind ganz normale Objekte mit Eigenschaften und Methoden

Event-Handler und Callback-Funktionen

Funktionale Programmierung

Kontext einer Funktion: Das Schlüsselwort this

Kontext mit call und apply beeinflussen

...

...