Webdesign mit CSS, HTML und Javascript
Stil mit {stil}

Neue Kameras und Objektive | Bildgestaltung und Bildbearbeitung
Fotografie von ihrer besten Seite: foto.5lux.de
Jul 2008
Funktionen in JavaScript – Anonyme Funktionen

Wenn Funktionen sehr einfach sind, verbessern anonyme Funktionen die Lesbarkeit und halten den Code besser zusammen.
Anonyme Funktionen sind Funktionen ohne Namen, die sofort ausgeführt werden.
Eine anonyme Funktion hat Zugriff auf jede Variable, die bei der Definition der Funktion sichtbar war, einschließlich lokaler Variablen. Das macht anonyme Funktionen so schön einfach.
| rot | gelb | grün | blau |
| Haus | Sonne | Wald | Fluss |
| 1002 | 4711 | 2048 | 1024 |
Ein klassischer Rollovereffekt, der die Hintergrundfarbe von Tabellenreihen beim hovern mit der Maus ändert, ruft zwei Funktionen auf: beim Ereignis onmousever die Funktion over() und beim Ereignis onmouseout die Funktion out().
| Normaler Funktionsaufruf | Anonyme Funktion |
var rows = document.getElementsByTagName( 'tr' );
for (var i=0; i<rows.length; i++) {
rows[i].onmouseover = over;
rows[i].onmouseout = out;
}
function over()
{
this.style.backgroundColor = "silver";
}
function out()
{
this.style.backgroundColor = "white";
}
|
var rows = document.getElementsByTagName( 'tr' );
for (var i=0; i<rows.length; i++) {
rows[i].onmouseover = function() {
this.style.backgroundColor = "silver";
}
rows[i].onmouseout = function() {
this.style.backgroundColor = "white";
}
}
|
Die beiden anonymen Funktionen ersetzen den Funktionsaufruf, werden aber ansonsten genauso notiert wie normale Funktionen: Zwischen der öffnenden und schliessenden geschweiften Klammer stehen dieselben Anweisungen, die auch in der normalen Funktion gestanden hätten. Da sie innere Funktionen sind, gewähren sie Anweisungen außerhalb der Funktion, in der sie liegen, keinen Zugriff.
Eine anonyme Funktion kann auch innerhalb eines Ausdrucks definiert werden.
Rekursive Funktionen
Rekursive Funktionen rufen sich selber innerhalb des Funktionskörpers auf. Nie waren rekursive Funktionen so wertvoll wie heute, da die Baumstruktur des DOM nach eleganten Verfahren zur Analyse des DOM-Baums ruft.
window.onload = initRekursion;
var allTags = new Array();
function initRekursion()
{
var form = document.getElementById( 'jsfuncRekursion' );
form.onsubmit = function() {
countTags( document.body );
alert( allTags.length );
return false;
}
}
Das Skript ruft initRekursion() auf, wenn das Dokument vollständig im Browserfenster geladen ist. Die erste Anweisung in initRekursion() sucht das Formular mit dem id-Attribut jsfuncRekursion und wartet auf das Absenden des Formulars. Die anonyme Funktion macht nichts anderes, als countTags() mit einem Parameter aufzurufen – dem BODY-Element des Dokuments – und anschliessend die Anzahl der gefunden Tags auszugeben.
function countTags( obj )
{
var elems = obj.childNodes;
for (var i=0; i<elems.length; i++) {
if (elems[i].nodeType == 1) {
allTags.push( elems[i].nodeName );
countTags( elems[i] );
}
}
}
In countTags(obj) sitzt die Rekursion: Die Funktion erwartet einen Elementknoten als Argument und liest als erstes alle Kindknoten des Arguments in das Array elems. In der for-Anweisung sieht sich die Funktion jeden Kindknoten an und wenn ein Kindknoten ein Elementknoten ist (if (elems[i].nodeType == 1)), der selber wieder Kindknoten haben kann, legt die Anweisung allTags.push(elems[i].nodeName); den Namen des Elementknotens im globalen Array allTags ab und ruft sich selbst mit dem Elementknoten auf. Das war's schon. Rekursionen sind fast immer im wahrsten Sinne des Wortes „unvorstellbar“ banal.
Rekursive anonyme Funktionen
Wer das Konzept der anonymen Funktionen mag, fragt sich jetzt natürlich sofort, ob und wie anonyme Funktion rekursiv aufgerufen werden, da sie ja keinen Namen haben.
In jeder Funktion existiert ein Arguments-Objekt, das neben der bekannten Eigenschaft length die selten benutzte Eigenschaft callee hat. callee gibt den Funktionskörper der aktuell ausgeführten Funktion zurück. Anonyme Funktionen verwenden die callee-Eigenschaft des Arguments-Objekts, um sich selber rekursiv aufzurufen.
<form action="jsFunktionen.shtml" method="get" id="jsfuncCallee"> <p><input type="text" name="mittel" id="mit0" /></p> <p><input type="submit" value="Mittel berechnen" /></p> </form>
Das Formular berechnet den Mittelwert einer beliebigen Anzahl von Eingaben. Jedes Mal, wenn der Benutzer einen Wert in ein Feld eingibt, erzeugt die anonyme Funktion ein neues Feld für die nächste Zahl und registriert sich selbst als Event Handler für das neue Feld.
var wert = document.getElementById( 'mit0' );
wert.onfocus = function() {
this.onfocus = null;
var newInput = this.cloneNode();
this.parentNode.appendChild(document.createElement( 'br' ));
this.parentNode.appendChild( newInput );
newInput.onfocus = arguments.callee;
};
Die erste Anweisung var wert = document.getElementById('mit0'); liest das Element mit der id mit0 ein – das ist das anfängliche Eingabefeld des Dokuments. Wenn das Feld in den Fokus kommt (beim Klick der Maus in das Feld oder bei einer Navigation mit der Tastatur) meldet this.onfocus = null; die Registrierung für das Ereignis ab, damit unentschlossene Benutzern nicht mit jedem Klick in ein Eingabefeld unzählige Eingabefelder erzeugen.
Die nächste Anweisung clont ein neues Eingabefeld und fügt on the fly ein BR- und direkt danach das neu erzeugte INPUT-Element in das Formular ein. Die Rekursion sitzt in der letzten Zeile der anonymen Funktion: newInput.onfocus = arguments.callee;. Die anonyme Funktion registriert sich selbst als Event Handler, wenn das neue Eingabefeld in den Fokus kommt, denn arguments.callee enthält genau die anonyme Funktion.
call by value und call by reference
Bei der Übergabe einer Variablen an eine Funktion benutzt die Funktion den Wert der Variablen für Berechnungen. Selbst wenn der Variablen innerhalb der Funktion ein neuer Wert zugewiesen wird: Außerhalb der Funktion ändert sich der Wert der Variablen nicht. Diese Mimic wird als call by value bezeichnet, denn der Funktion wird nur der Wert der Variablen übergeben, nicht aber die Referenz auf die Speicherstelle.
function machWas( arg )
{
arg = 17;
}
function caller()
{
var myVar = 2000;
machWas(myVar);
alert(myVar);
}
Nach dem Aufruf von machWas aus der Funktion caller ist myVar weiterhin 2000. Der Funktion machWas wurde im Grunde genommen nur eine Kopie von myVar übergeben.
Es gibt eine weitere Technik bei der Übernahme von Variablen in Funktionsargumente: call by reference. Bei dieser Technik kann die Funktion nicht nur die Variable für interne Berechnungen verwenden, sondern den Wert der Variablen auch verändern.
In JavaScript ist call by value bei Funktionsaufrufen mit Argumenten der Normalfall. Wenn allerdings Objekte als Argumente an eine Funktion übergeben werden, kann eine call by reference-Mimic durchgeführt werden – d.h., das Objekt wird tatsächlich innerhalb der Funktion geändert und nicht einfach nur sein Wert in Berechnungen verwendet.
var myObject = new Object();
myObject.val = 2000;
function machWas( arg )
{
arg.val = 4000;
}
machWas( myObject.val );
alert( myObject.val );
In anderen Programmiersprachen gibt es Mechanismen, um Funktionsaufrufe als call by reference auch dann zu erzwingen, wenn das Argument kein Objekt ist. In PHP z.B. wird dem Argument ein „&“ vorangestellt, damit es beim Funktionsaufruf als Referenz auf die Speicherstelle und nicht einfach als Wert der Variablen benutzt wird (machWas(&arg)). Einen solchen Mechanismus besitzt JavaScript nicht.
Funktions-Objekte
Ab Javascript 1.1 können Funktionen durch den Funktions-Konstruktor erzeugt werden.
var summe = new Funktion ( "x", "y", "return x + y" );
Ab Javascript 1.2 können Funktionen als Funktions-Literal definiert werden. Funktions-Literale werden nur einmal geparst und bleiben dann statisch.
var summe = function( x,y ) { return x + y; }
Funktions-Literale ähneln dem Funktions-Konstruktor, benutzen aber eine „normale“ Syntax, um einer Variablen eine anonyme Funktion als Wert zuzuweisen. Diese Funktionen sind anonym, da sie keinen Namen haben:
var quadrat = function( zahl ) {
return zahl * zahl;
}
Das Funktions-Literal kann auch einen Namen haben, aber dieser Name gilt nur innerhalb der Funktion. Auf diese Weise können rekursive Funktionen realisiert werden:
var calc = function summe( x ) {
if (x < 2) {
return 1;
} else {
return x + summe( x - 1 );
}
}
…
z = calc( 40 ); // Dieser Aufruf ist korrekt
z = summe( 40 ); // Dieser Aufruf funktioniert nicht
Funktionsobjekte
Der Funktions-Konstruktor Function in Javascript erlaubt das Erzeugen einer Variablen und Zuweisen einer Funktion als Wert. Das vordefinierte Objekt Function gibt einen String an, der als Funktion interpretiert wird. Der Funktions-Konstruktor übernimmt eine beliebige Zahl von Argumenten, die alle als String übergeben werden, wobei das letzte Argument die Anweisungen der Funktion darstellen.
// Muster var myFunction = new Function ( [arg1, arg2, …, argN], Funktionskörper ); // Beispiel var sum = new Function( 'x', 'y', 'return x+y;' );
myFunction ist der Name einer Variablen oder Eigenschaft eines existierenden Objekts oder ein Objekt gefolgt von einem Event Handler
body.onload = new Function();
Der Aufruf der Funktion erfolgt über den Namen der Variablen, aber die Variable enthält keinen Wert, sondern eine Referenz auf die Funktion als Wert.
summe = sum( 40, 2 );
Funktions-Objekte werden bei jedem Aufruf entwickelt und dementsprechend ist ihre Effizienz gegenüber der Deklaration einer Funktion, die einmalig zu Beginn der Ausführung geparst wird, geringer. Funktions-Objekte bei jedem Aufruf geparst, so dass der String der Argumente und der Funktionsblock aus dynamisch zugewiesenen Werten bestehen kann und die Funktion im Grunde genommen bei jedem Aufruf neu geschrieben wird.
var c; var calc = new Function( 'x', 'y', c ); c = 'x + y'; sum = calc( 40, 2 ); // sum ist 42 c = 'x / y'; div = calc( 40, 2 ); // div ist 20
Eigenschaften von Funktionen
Da Funktion in Javascript Objekte sind, haben Funktionen auch Eigenschaften. Eine Eigenschaft length gibt die Anzahl der Argumente zurück, die von der Funktion erwartet werden.
Eine andere Eigenschaft ist die prototype-Eigenschaft. Wie bei jedem Objekt können individuelle Eigenschaften für Funktionen definiert werden. Das erlaubt das Erzeugen von Werten, die wiederholte Aufrufe der Funktion „überleben“ (man sagt auch: persistente Werte). Um eine neue Eigenschaft für eine Funktion zu erzeugen, wird ihr einfach ein Wert zugewiesen.
quad.counter = 0; // Initialisierung;
function quad( x )
{
quad.counter++;
Anweisungen;
…
}
Bei jedem Aufruf von quad wird quad.counter um Eins inkrementiert.