Rekursive Funktionen in Javascript

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="rekursive-Funktionen.html" 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.