Hallo!
Meine Frage ist nun wie kann ich das "flexibel" machen?
Ich dachte mit "id = id;" in der getStatus Funktion mache ich die ID global?
Flexibel machst du JavaScript NICHT, wenn du anfängst, globale Variablen einzuführen. Globale Variablen solltest du möglichst vermeiden, zumal solche mit generischen Namen wie »id«.
Wenn bereits eine Funktionsvariable id existiert (was der Fall ist, wenn sie in der Parameterliste deklariert ist), so legt die Zuweisung id = id;
in einer Funktion keine globale Variable an. Da müsstest du schon explizit window.id = id;
schreiben. Doch wie gesagt solltest du davon absehen.
Es kommt in JavaScript häufig vor, dass man verschiedene asynchrone Funktionen hat, die untereinander auf gemeinsame Daten zugreifen sollen. Das passiert insbesondere bei Event-Handlern, Callbacks sowie bei setTimeout/setInterval.
Es gibt verschiedene Möglichkeiten, wie sich der gemeinsame Zugriff auf gewisse Variablen ermöglichen lässt, OHNE globale Variablen anzulegen. Eine gute Idee ist, erst einmal alle Daten in einem Objekt zu gruppieren, z.B. in Modulen oder Instanzen. Dann sorgt man dafür, dass Methoden in deren Kontext aufgerufen werden, man also mit this
auf das gemeinsame Objekt zugreifen kann. Hierfür lassen sich Closures verwenden oder explizites Binding von Funktionen.
Angenommen, wir benutzen ein Object-Literal zur Gruppierung und nutzen dann Function.prototype.bind zum Function-Binding:
// Object-Literal, der alle Daten gruppiert
var StatusUpdater = {
// Konfiguration - hier steht alles flexible
id : 1,
url : "http://localhost/get_status.php",
targetElementId : 'gadgetContent',
interval : 5000,
// Platzhalter-Eigenschaften, werden im Laufe gefüllt
targetElement : null,
xhr : null,
targetElement : null,
// Methoden
getXHR : function () {
return new XMLHttpRequest();
},
getStatus : function () {
// Rufe StatusUpdater-Methode auf und speichere Rückgabe in StatusUpdater-Eigenschaft
this.xhr = this.getXHR();
if (!this.xhr){
alert ("Browser does not support HTTP Request");
return;
}
var rand = Math.ceil(Math.random() * 100000);
url = url + "?id=" + id + "&ref=" + rand;
// Erzeuge eine an StatusUpdater gebundene Funktion, nutze diese als Event-Handler
this.xhr.onreadystatechange = this.handleResponse.bind(this);
this.xhr.open("GET", this.url, true);
this.xhr.send(null);
},
handleResponseStatus : function () {
if (this.xhr.readyState != 4) return;
if (!this.targetElement) {
this.targetElement = document.getElementById(this.targetElementId);
}
this.targetElement.innerHTML = this.xhr.responseText;
// Erzeuge eine gebundene Funktion, nutze diese für setTimeout
setTimeout(this.getStatus.bind(this), this.interval);
}
};
(ungetestet, es geht ums Prinzip)
Anstatt den vielen »this.« könnte man auch »StatusUpdater.« schreiben. Aber eigentlich sollten die Funktionen nicht darauf festgelegt sein, in dessen Kontext aufgerufen zu werden. Ändert man mal den Namen, kopiert Funktionen um oder verwendet sie wieder, so wäre der Aufwand enorm. Deswegen ist die Nutzung des this-Kontextes schon sinnvoll.
Um sich ein wenig Tipparbeit zu sparen und den Code übersichtlicher zu machen, kann man für häufig verwendete Variablen lokale Shortcuts verwenden, z.B. var xhr = this.xhr;
.
Allgemein gesagt sind Funktionen, lokale Variable und Verschachtelung von Funktionen das Mittel der Wahl, um Daten zu kapseln und gleichzeitig zwischen verschiedenen Funktionen zu teilen. Siehe auch Closures.
Mathias