molily: setTimeout

Beitrag lesen

Deine Funktion ist eine Methode des Objektes, in dem du dich befindest.

Es ist bloß eine lokale Funktion. Die ist intern am Variablenobjekt des Execution Contexts gespeichert, das durch den Funktionsaufruf erzeugt wurde.

setTimeout(methode, ...) hingegen legt den Aufruf „auf Halde“, um ihn später durchzuführen - allerdings passiert das dann ausserhalb des Kontextes deines Objektes, und damit ist die Methode dort gar nicht mehr verfügbar.

Der Begriff Kontext ist hier irreführend und du verwendest ihn gleich mit zwei unterschiedlichen Bedeutungen. (Die von mir im verlinkten Artikel verwendete Bedeutung ist auch nicht so ganz schlau.)

setTimeout kann man entweder ein Funktionsobjekt übergeben. Die Referenz auf das Funktionsobjekt muss dort, wo setTimeout aufgerufen wird, natürlich verfügbar sein. D.h. wenn ich setTimeout(foo, 1000) schreibe, dann muss der Bezeichner foo zu einem Funktionsobjekt auflösbar sein.
Alternativ kann man setTimeout einen String übergeben. Dieser Code wird dann mit eval() ausgeführt.

Der Execution Context in beiden Fällen ist der globale Kontext. Das bedeutet, dass this auf das globale Objekt (window) verweist. Das, worauf this zeigt, bezeichne ich im Artikel als Kontext. Das hat mit »Methode ist dort nicht verfügbar« nichts zu tun. Verfügbarkeit von Objekten (Referenzierbarkeit) wird immer über den Scope entschieden. Intuitiv würde man eher den als Kontext bezeichnen... wie gesagt, der Begriff ist nicht so tauglich. Der Execution Context beinhaltet sowohl die this-Referenz als auch die maßgebliche Scope Chain.

Im Falle der Übergabe eines Strings an setTimeout, z.B. "foo()", wird der Bezeichner »foo« am globalen Objekte gesucht. Denn die Scope Chain, also die Liste der Objekte, bei denen nach entsprechenden Membern gesucht wird, enhält nur das globale Objekt. foo muss also eine globale Funktion sein, sonst gibt es eine Exception. Und das war nicht der Fall im geposteten Code.

Im Falle der Übergabe einer Funktion muss kein Bezeichner aufgelöst werden, sie steht bereits als Referenz zur Verfügung. Die Referenz hat kein base object, deshalb wird das globale Objekt angenommen - daher this == window. (Selbst man setTimeout(objekt.methode, 1000) notieren wurde, dann geht diese Basis verloren.)

Ganz anderes thema: Welche Variablen dem Code IN der Funktion zur Verfügung stehen, hängt davon ab, in welchem Execution Context sie ERZEUGT wurde. Wenn wir uns dieses Beispiel noch einmal ansehen:

function new_tab_parttopic()  {
   var div_height = document.getElementById("new_tab_area");
   function scroll_down() {
      var height_change = div_height.offsetHeight;
      div_height.style.height = height_change + 100 + "px";
   }
   setTimeout(scroll_down, 10000);
}

Hier haben wir es mit einer Closure zu tun. Die Scope Chain der scroll_down-Funktion enthält das eigene Variablenobjekt, das Variablenobjekt des new_tab_parttopic()-Aufrufs und schließlich das globale Objekt. Damit kann man darin - auch später noch, wenn scroll_down durch setTimeout im globalen Execution Context ausgeführt wird - auf die Variable div_height zugreifen. Der Execution Context samt Variablenobjekt wird nämlich erhalten.

Mathias