Methodenaufruf
Kristin
- javascript
Hi!
ich habe das Problem, dass ich innerhalb von "xmlRequest.onreadystatechange" die Methode test2 nicht aufrufen kann.
Folgende Fehlermeldung erhalte ich:
Opera 9.80
JavaScript - http://localhost/test.htm
Unknown thread
Error:
name: TypeError
message: Statement on line 344: Type mismatch (usually non-object value »» supplied where object required)
stacktrace: Line 344 of inline#1 script in http://localhost/test.htm
this.test2(obj);
...
Iceweasel 3.0.11
Fehler: this.test2() is not a function
Quelldatei: http://localhost/test.htm
Zeile: 352
Internet Explorer 8
Details zum Fehler auf der Webseite
Benutzer-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Zeitstempel: Wed, 8 Jul 2009 18:49:04 UTCMeldung: Das Objekt unterstützt diese Eigenschaft oder Methode nicht.
Zeile: 352
Zeichen: 15
Code: 0
URI: http://localhost/test.htm
wie muss ich die Methode test2 korrekterweise aufrufen?
gekürztes Beispiel:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="de" xml:lang="de">
<head>
<title>Test</title>
<meta http-equiv="Content-Type" content="text/html, charset=utf-8" />
<script type="text/javascript">
<!--
// <![CDATA[
[code lang=javascript]function Test(){
this.test1 = function(obj){
...
xmlRequest = (window.XMLHttpRequest) ? new XMLHttpRequest() : ((window.ActiveXObject) ? new ActiveXObject("Microsoft.XMLHTTP") : false);
xmlRequest.open('GET', url, true);
this.delEntries(obj);
xmlRequest.onreadystatechange = function(){
...
this.test2(obj);
}
xmlRequest.send(null);
}
this.test2 = function(obj){
alert('test2');
}
}
test = new Test();
// ]]>
//-->
</script>
</head>
<body>
<form action="">
<p><input type="button" value="test" onclick="test.test1(this);" /></p>
</form>
</body>
</html>[/code]
ps. warum werden bei den Browsern jeweils andere Zeilennummern ausgegeben?
Kristin
Liebe Kristin,
das Schlüsselwort "this" deutet nicht immer auf das Objekt, das Du in Deinem Code vermutest.
Wenn Du in einem XHR-Objekt (XmlHttpRequest-Objekt) einen Eventhandler (also die Funktion/Methode onreadystatechange) nutzt, dann deutet "this" in dieser Funktion immer auf das XHR-Objekt, keinesfalls jedoch auf dasjenige Objekt (eine Instanz von "Test"), dessen Methode "test1" dieses XHR-Objekt definiert hat.
xmlRequest = (window.XMLHttpRequest) ? new XMLHttpRequest() : ((window.ActiveXObject) ? new ActiveXObject("Microsoft.XMLHTTP") : false);
xmlRequest.open('GET', url, true);
Hier definierst Du ein XHR-Objekt namens xmlRequest. Soweit OK.
this.delEntries(obj);
Hier rufst Du eine Methode der Instanz des "Test"-Objektes auf, nämlich "delEntries".
xmlRequest.onreadystatechange = function(){
...
this.test2(obj);
}
So. Hier definierst Du eine anonyme Funktion, die Du dem Eventhandler des XHR-Events als Wert zuweist. Immer wenn dieser ausgeführt wird, dann zeigt "this" auf das XHR-Objekt, dessen Eventhandler gefeuert hat - logisch oder? Wie sonst sollte denn JavaScript wissen, welches XHR-Objekt (dessen könntest Du mehrere instanziiert haben!) denn nun diesen ReadyStateChange hatte?
Man löst solche Dinge zum Beispiel mit einer "Closure", indem man eine lokale Variable definiert, um dann in einer Funktion, die "unterhalb" des aktuellen Geltungsbereiches definiert wird, darauf zurückgreift.
var Test = function () {
this.test1 = function () {
var xmlRequest = new XMLHttpRequest(); // ich kürze hier ab!
var t = this; // diese Variablen wird nachher benötigt
xmlRequest.onreadystatechange = function () {
// tu was...
t.test2(); // t verweist auf die Instanz von "Test"
// "t" ist deshalb hier bekannt, da diese anonyme Funktion
// im Geltungsbereich von "this.test1" definiert wird, und
// damit auf die lokalen Variablen von "this.test1" zugreifen
// kann.
};
};
};
Liebe Grüße,
Felix Riesterer.
Hi Felix :-)
danke! das funktioniert :)
Kristin
Hi,
Opera 9.80
stacktrace: Line 344 of inline#1 script in http://localhost/test.htm
Iceweasel 3.0.11
Zeile: 352
Internet Explorer 8
Zeile: 352
ps. warum werden bei den Browsern jeweils andere Zeilennummern ausgegeben?
weil sie sich auf unterschiedliche Dinge beziehen. Vor dem Inline Script befinden sich 8 Zeilen HTML-Code. Ebenso einfach ist es zu erklären, warum der IE in diversen Versionen bei Auslagerung des Scripts in eine separate Ressource eine um 1 erhöhte Zeilennummer gegenüber allen anderen Browsern ausgibt: Weil es der IE ist.
Cheatah
@@Kristin:
nuqneH
<?xml version="1.0" encoding="utf-8"?>
Warum schickst du IE < 7 in den Quirksmodus? [Jendryschik] Die XML-Deklaration ist überflüssig, wenn als Zeichencodierung UTF-8 oder UTF-16 verwendet wird.
<script type="text/javascript">
<!--
[…]
//-->
</script>
Und die Auskommentierung von JavaScript-Code ist noch überflüssiger. Weg damit!
Qapla'
Hi!
nuqneH
?
<?xml version="1.0" encoding="utf-8"?>
Warum schickst du IE < 7 in den Quirksmodus? [Jendryschik] Die XML-Deklaration ist überflüssig, wenn als Zeichencodierung UTF-8 oder UTF-16 verwendet wird.
macht der Gewohnheit ;-)
<script type="text/javascript">
<!--
[…]
//-->
</script>Und die Auskommentierung von JavaScript-Code ist noch überflüssiger. Weg damit!
wenn ich mich nicht täusche, hatte ich das damals, vor 6-7 Jahren auf selfhtml so gesehen.
Kristin
@@Kristin:
nuqneH
nuqneH
?
Und die Auskommentierung von JavaScript-Code ist noch überflüssiger. Weg damit!
wenn ich mich nicht täusche, hatte ich das damals, vor 6-7 Jahren auf selfhtml so gesehen.
Wenn ich mich nicht täusche, war das damals, vor 6-7 Jahren schon völlig überflüssig. Heute gibt es in freier Wildbahn keinen Bowser mehr, der dies nötig hätte.
Qapla'
Hi!
nuqneH
nuqneH
?
ich versteh trotzdem nur bahnhof :-)
Und die Auskommentierung von JavaScript-Code ist noch überflüssiger. Weg damit!
wenn ich mich nicht täusche, hatte ich das damals, vor 6-7 Jahren auf selfhtml so gesehen.
Wenn ich mich nicht täusche, war das damals, vor 6-7 Jahren schon völlig überflüssig. Heute gibt es in freier Wildbahn keinen Bowser mehr, der dies nötig hätte.
meines Wissens stört das den Browsern nicht, also warum sollte man es entfernen, wenn damit Fehler bei Uralt-Browsern verhindert werden kann?
Kristin
@@Kristin:
nuqneH
meines Wissens stört das den Browsern nicht
Vorsicht! Sobald du den Decrement-Operator '--' im Script verwendest, hast du einen fetten XHTML-Fehler, denn '--' darf nicht innerhalb eines Kommentars vorkommen. [XML10 §2.5]
also warum sollte man es entfernen […]
Um den Decrement-Operator verwenden zu können.
Andere Frage: Warum sollte man es einfügen?
[…] wenn damit Fehler bei Uralt-Browsern verhindert werden kann?
(1) Solche Uralt-Browser gibt es nur noch im Museum.
(2) In solchen Uralt-Browsern hättest du noch weitaus andere Darstellungsprobleme als die Ausgabe von JavaScript-Quelltext.
Qapla'
also warum sollte man es entfernen […]
Um den Decrement-Operator verwenden zu können.
Und die Kommentare sind in XHTML problematisch und können verhindern, dass sich das Dokument als XHTML verarbeiten lässt (das macht zwar niemand, aber die Möglichkeit sollte man sich nicht verbauen, wenn man schon XHTML einsetzt). Denn XML-Parser können Kommentare entfernen, bevor sie den DOM-Baum an die Anwendung weitergeben (allerdings tun das die XML-Parser der Browser meines Wissens nicht). In dem Fall wäre der JavaScript-Code verschwunden und würde nicht ausgeführt.
Mathias
Liebe Kristin,
nuqneH
?ich versteh trotzdem nur bahnhof :-)
Gunnar liebt es klingonische Grüße zu notieren. Als Fan von Star-Trek ist das eben sein Ding.
meines Wissens stört das den Browsern nicht, also warum sollte man es entfernen, wenn damit Fehler bei Uralt-Browsern verhindert werden kann?
Du schreibst validen Code nach XHTML1.0 stric, korrekt? Dann notierst Du Deine "Kommentare" bitte so:
<script type="text/javascript">//<![CDATA[
var javascript_code = "...";
//]]></script>
Die XML-Spezifikation verlangt, dass Du Sonderzeichen maskierst. Darunter fallen '<', '>', '&' und manchmal (bei Attributwerten) auch '"'. Und genau diese Zeichen haben in JavaScript auch besondere Bedeutung. Wenn Du zum Beispiel in JavaScript diese Zeile hättest
if (a < b) alert("kleiner!");
dann müsstest Du sie eigentlich XHTML-konform so notieren:
if (a < b) alert("kleiner!");
Aber damit würde Dir ein Syntax-Fehler in der JavaScript-Konsole erscheinen und Dein Script abbrechen.
Daher notiert man in XHTML das besser als CDATA, die vom XML-Parser nicht geparst wird, also auch nicht als XHTML-Code verstanden wird, und deshalb unmaskierte Spezialzeichen enthalten darf. Damit nun der JavaScript-Interpreter mit dem einleitenden und beendenden CDATA-"Tag" kein Problem bekommt, stellst Du das hinter einen Doppel-Slash, der für JavaScript ein Kommentarzeichen darstellt. Problem XHTML1.0-strict-konform gelöst!
Liebe Grüße,
Felix Riesterer.
@@Felix Riesterer:
nuqneH
dann müsstest Du sie eigentlich XHTML-konform so notieren:
if (a < b) alert("kleiner!");
Aber damit würde Dir ein Syntax-Fehler in der JavaScript-Konsole erscheinen und Dein Script abbrechen.
Bei Verarbeitung als 'text/html'. Bei Verarbeitung als 'application/xhtml+xml' wird (wenn der Script-Bereich als PCDATA belassen wird) die Zeichenreferenz '<' zu '<' aufgelöst, bevor der JavaScript-Code ausgeführt wird. Dann gibt’s keinen Syntax-Fehler.
Problem XHTML1.0-strict-konform gelöst!
Das Problem ist die HTML-Konformität. In XHTML müsste man '<' statt '<' schreiben, dann kann das Dokument aber nicht als 'text/html' verarbeitet werden. Deshalb ist es ratsam, Script-Bereiche als CDATA zu markieren.
Noch ratsamer ist es freilich, keinen JavaScript-Code im HTML zu haben, sondern extern.
Qapla'
Hallo!
Zur Hintergrund-Lektüre: Methoden eigener Objekte in anderen Kontexten ausführen und ff. bis Anwendung von Closures
Die onreadystatechange-Handlerfunktion ist zwar hier keine Methode deines Objektes, aber das Kontext-Problem (this zeigt nicht auf das Instanzobjekt) ist dasselbe.
Mathias