15.2 JavaScript Debugger   Unterhttp://www.mozilla.org/projects/venkman/ stellt das Mozilla-Projekt einen kostenlosen Debugger für JavaScript-Programme zur Verfügung. Dieser bietet die Basiseigenschaften eines Debuggers, also das Setzen von Breakpoints und die Anzeige aktueller Variablenwerte während der Ausführung (dazu jeweils später mehr). Nach der Installation integriert sich der Debugger in das Menü des Browsers und kann perExtras NJavaScript Debugger gestartet werden.  Hier klicken, um das Bild zu Vergrößern
Abbildung 15.2 Der Bildschirm nach dem Starten des Debuggers
15.2.1 Wo ist der Fehler?   Nun benötigen wir noch ein fehlerhaftes Programm. Kaufen Sie also ein Konkurrenzwerk (war nur ein Scherz), oder werfen Sie einen Blick auf das folgende kurze Programm: <html><head><title>Debugger</title><script type="text/javascript"><!--var summe = 0;var zaehler = 0;var obergrenze;function ungerade() { zaehler++; var summe = summe + zaehler; if (zaehler < obergrenze) { gerade(); }}function gerade() { zaehler++; var summe = summe + zaehler; if (zaehler<obergrenze) { ungerade(); }}function sum(n) { obergrenze = n; ungerade(); return summe;}//--></script></head><body><script type="text/javascript"><!--document.write(sum(100));//--></script></body></html>Das Prinzip des obigen Programms ist relativ einfach. Die Hauptfunktion istsum(n), die die Summe der Zahlen von1 bisn berechnet. Um das Ganze ein wenig komplizierter (und damit fehlerträchtiger) zu machen, gehen wir wie folgt vor: In der globalen Variablesumme wird das aktuelle Zwischenergebnis gespeichert, und in der globalen Variablezaehler merkt sich das Programm, welche Zahlen bis jetzt schon aufsummiert worden sind. Zunächst wird die Funktionungerade() aufgerufen, die zunächst den Zähler um 1 erhöht (beim ersten Aufruf: auf 1) und dann den Wert des Zählers zur Zwischensumme addiert. Danach wird die Funktiongerade() aufgerufen, die genau dasselbe erledigt: zunächst Zähler erhöhen (beim ersten Aufruf: auf 2) und dann den Zählerwert zur Zwischensumme hinzuzählen. Sobald der Zähler die Obergrenze erreicht hat, wird abgebrochen. Wenn man der Legende Glauben schenkt, hat Gauß schon im Grundschulalter diese Aufgabe gelöst. Sein Lehrer wollte ihn ein wenig beschäftigen und bat ihn, die Zahlen von 1 bis 100 zu addieren. Der kleine Gauß hat eine Weile überlegt und herausgefunden, dass man die Summe der Zahlen von1 bisn mit der Formeln(n+1) berechnen kann; bein=100 kommt5050 heraus. Wenn Sie das Skript im Browser aufrufen (starten Sie vorher unbedingt den Debugger, wie oben beschrieben!), werden Sie jedoch erstaunt feststellen, dass als Ergebnis 0 angezeigt wird. Woran kann das liegen? Der Debugger weiß hier vielleicht Rat. Starten Sie den Debugger, so Sie im oberen Bereich unter anderem die (absichtlich) fehlerhafte Datei entdecken. Klicken Sie doppelt auf den Dateinamen, und der Quellcode erscheint (falls nicht, wählen Sie die MenüoptionView NShow/Hide NSource Code).  Hier klicken, um das Bild zu Vergrößern
Abbildung 15.3 Der Quellcode im Debugger
15.2.2 Breakpoints   Um den Debugger wirklich nutzen zu können, müssen Sie einen so genannten Breakpoint setzen. Die wörtliche Übersetzung, »Unterbrechungspunkt« oder auch »Haltepunkt«, kommt der Wahrheit schon sehr nahe. Sobald der JavaScript-Interpreter beim Haltepunkt angekommen ist, wird die Skriptausführung unterbrochen und Sie können beispielsweise auf den aktuellen Wert aller Variablen zugreifen. Breakpoints beziehen sich immer auf eine Zeile; die Programmausführung wird unterbrochen, bevor der Code in der Zeile ausgeführt wird. Prinzipiell gibt es zwei Möglichkeiten, einen Breakpoint zu setzen: | Klicken Sie in die entsprechende Zeile, und wählen Sie im Kontextmenü (rechte Maustaste) den EintragSet Breakpoint. |
| Klicken Sie in der entsprechenden Zeile in den dunkelgrauen Bereich am linken Rand. |
Egal welche der beiden Methoden Sie einsetzen, Sie sehen danach eine rote Markierung im linken Rand, wodurch das Vorhandensein eines Breakpoints angedeutet wird. In diesem Beispiel sollten Sie den Breakpoint in die Zeilezaehler++ der Funktionungerade() setzen. Tun Sie das, und laden Sie im Browserfenster das (fehlerhafte) Skript erneut. Nach kurzer Zeit kommt das Debugger-Fenster in den Vordergrund; die aktuelle Position der Skriptausführung ist durch eine gelbe Hintergrundmarkierung gekennzeichnet.
15.2.3 Watches    Hier klicken, um das Bild zu Vergrößern
Abbildung 15.4 Watches werden in der Konsole angezeigt. Es ist nun an der Zeit, die Werte einiger Variablen zu betrachten. UnterView NShow/Hide NWatches können Sie das Fenster für so genannteWatches einblenden, falls das noch nicht geschehen ist. Watches sind Variablen oder Ausdrücke, deren Wert Sie permanent überwachen möchten. Im Kontextmenü der Watches-Anzeige finden Sie den EintragAdd Watch Expression, mit dem Sie eine neue Watch angeben können. Es empfiehlt sich in diesem Beispiel, ein genaueres Augenmerk auf die Variablensumme undzaehler zu werfen. Erstellen Sie also zwei Watches – eine für die Variablesumme und eine für die Variablezaehler (alternativ können Sie auch im FensterLocale Variables einen Wert auf alle lokalen Variablen werfen). Im Watches-Fenster werden die Variablennamen dann angezeigt, nebst allen zugehörigen Werten. Sobald sich der Wert einer der Variablen ändert, wird der neue Wert in der Konsole angezeigt. Sie müssen eigentlich nur noch das Programm weiterlaufen lassen (SchaltflächeContinue) und dabei zusehen, was geschieht.
 15.2.4 Schrittweise Programmausführung   Sie sehen in der Symbolleiste ganz rechts fünf Schaltflächen, mit denen Sie die Skriptausführung wieder in Gang setzen können. Der Reihe nach haben diese die folgenden Funktionen: | Stop: Die Skriptausführung wird angehalten. |
| Continue: Das Programm wird weiter ausgeführt, bis es entweder am Ende ankommt oder wieder bei einem Breakpoint stehen bleiben muss. |
| Step Over: Es wird zur nächsten Zeile in der aktuellen Funktion gesprungen. Sollte der Interpreter am Ende der Funktion angelangt sein, verhält sich die Schaltfläche wieRun. |
| Step Into: Es wird zur nächsten Zeile des Programmcodes gesprungen, ganz egal, ob diese innerhalb der aktuellen Funktion liegt oder außerhalb. |
| Step Out: Die aktuelle Funktion wird verlassen und das Programm weiter ausgeführt, bis es endet oder am nächsten Breakpoint stehen bleiben muss. |
| Profile: Es wird ein so genanntes Profiling des Skripts durchgeführt: Welcher Teil dauert wie lange? |
| Pretty Print: Quellcode wird »hübsch« formatiert. |
Beachten Sie nun genau, was geschieht, wenn Sie von der Zeilezaehler++ aus mitStep Into weiter vorgehen. Anfangs hatzaehler einen Wert von0 undsumme einen Wert vonvoid. Nach der Ausführung des Kommandoszaehler++ hatzaehler den Wert1, der Wert vonsumme hat sich nicht geändert. In der nächsten Zeile jedoch ändert sich der Wert vonsumme – aber nicht wie erhofft in1, sondern in ...NaN, not a number. Warum nur? Mit ein wenig Überlegung ist klar, wo der Fehler liegt. Vor der Anweisungsumme = summe + zaehler steht einvar. Dadurch wirdsumme innerhalb der Funktionungerade() – und analog dazu auch ingerade() – zu einer lokalen Variablen, deren Wert außerhalb der Funktion nicht sichtbar ist. Die Variablesumme ist aber eigentlich als globale Variable konzipiert.  Hier klicken, um das Bild zu Vergrößern
Abbildung 15.5 Die Variablesumme hat offensichtlich einen falschen Wert. Entfernen Sie sowohl in der Funktionungerade() als auch in der Funktiongerade() das Schlüsselwortvar vorsumme, brechen Sie im Debugger die Skriptausführung ab, und laden Sie die Seite im Browser neu. Ein Blick in den Debugger verheißt Gutes, denn nun wirdsumme anständig erhöht. Und wenn Sie nun noch den Breakpoint entfernen (zweimal in den dunkelgrauen Bereich klicken) und das Skript durchlaufen lassen, sehen Sie im Browser auch das korrekte Ergebnis – 5050. Wir haben zwar etwas länger gebraucht als der kleine Gauß, aber dafür durften wir ja auch nicht per Hand rechnen. |