Scope von eval() im IE anders als im FF???
Johanna
- javascript
Hallo ihr,
ich hab ein nerviges Problem, das mich schon den ganzen Sonntag beschäftigt.
DER KONTEXT:
Stark vereinfacht ist es so: über einen XHR bekomme ich vom Server z.B. folgendes HTML und folgendes JS als String geschickt:
- HTML: <a href="#" onclick="test()">click me</a>
- JS: "function test() { alert('TEST'); }"
Meine XHR Callback-Funktion für den Erfolgsfall fügt den HTML-Code in den DOM der Seite ein und wertet das JS per eval(...) aus.
DAS EIGENTLICHE PROBLEM:
Im Endeffekt kann ich das Problem also auf folgenden Testcode abbilden:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de" lang="de">
<head>
<title>Test</title>
<script type="text/javascript">
runScript = function(code) {
eval(code);
};
runScript ("function test() { alert('TEST'); }");
</script>
</head>
<body><a href="#" onclick="test()">click me</a></body>
</html>
Bei Klick auf den Link kommt es im obigen Bsp. sowohl im IE also auch im FF zum Fehler. Beide finden die Funktion "test" nicht, da der entsprechende String im Scope der Funktion "runScript()" ausgeführt wurde. Klar!
Also definiere ich die Funktion so:
runScript = function(code) {
window.eval(code);
};
Nun sollte doch die Funktion "test" im Scope des "window"-Objekts ausgeführt und damit an dieses "angehängt" werden. Da der Code in onclick etc. auch immer im Scope des "window"-Objekts ausgeführt wird (ist doch so, oder???) sollte doch nun ein Klick auf den Link ein Fenster mit "TEST" hervorbringen. DENKSTE!!! Firefox macht das ganze wie erwartet. Der IE meint jedoch: "Object expected" und zeigt auf die Zeile des Links.
WARUM??? Oder besser, wie kriege ich es hin, dass es in beiden Browsern funktioniert???
Würde ich übrigens den Funktionsstring so vom Server erhalten: "test = function() { alert('TEST'); };" funktionierts unverständlicherweise in beiden Browsern - sogar ohne "window." vor eval().
Leider ist der Funktionsstring und der String hinter onclick für mich nicht zu beeinflussen!!! Das heißt ich muss das oben geschilderte Problem für den IE lösen.
Kann mir da jemad helfen?
BITTE, BITTE, BITTE!
Grüße,
Johanna
Hallo,
runScript = function(code) {
window.eval(code);
};Nun sollte doch die Funktion "test" im Scope des "window"-Objekts ausgeführt und damit an dieses "angehängt" werden.
Ob du eval oder window.eval notierst, das sollte meines Wissens denselben Effekt haben.
Da der Code in onclick etc. auch immer im Scope des "window"-Objekts ausgeführt wird (ist doch so, oder???)
Nein, this zeigt auf das Elementobjekt.
sollte doch nun ein Klick auf den Link ein Fenster mit "TEST" hervorbringen.
Ich wüsste nicht, wieso.
DENKSTE!!! Firefox macht das ganze wie erwartet. Der IE meint jedoch: "Object expected" und zeigt auf die Zeile des Links.
Da staune ich eher über Firefox' Verhalten, das mir ein Sonderfall zu sein scheint. Konqueror pflichtet MSIE übrigens bei, Opera dafür Firefox.
WARUM???
Keine Ahnung, ehrlich gesagt. Firefox' und Operas Verhalten erscheint mir aber unlogisch, wenngleich diese Einrichtung natürlich praktisch ist, aber wertlos, solange die Browser sich nicht einig sind.
Würde ich übrigens den Funktionsstring so vom Server erhalten: "test = function() { alert('TEST'); };" funktionierts unverständlicherweise in beiden Browsern - sogar ohne "window." vor eval().
Wieso unverständlicherweise?
Mit »test = function () {}« oder »window.test = function () {}« legst du explizit eine globale Variable an. »function func () {}« hingegen ist in einer Funktion äquivalent zu »var func = function () {};«, das legt eine lokale Variable an.
Leider ist der Funktionsstring und der String hinter onclick für mich nicht zu beeinflussen!!!
Dann wirst du das Problem wohl nicht beheben können.
Schau dir auch mal diesen Thread an:
</archiv/2006/11/t140426/>
Mathias
Ob du eval oder window.eval notierst, das sollte meines Wissens denselben Effekt haben.
Anscheinend nicht, zumindest laut: http://blog.zimki.com/tomi/2006/08/07/javascript-eval
Da der Code in onclick etc. auch immer im Scope des "window"-Objekts ausgeführt wird (ist doch so, oder???)
Nein, this zeigt auf das Elementobjekt.
Schon, aber Funktionsaufrufe hierin funktionieren doch nur für solche Funktionen, die global sind, also am window-Objekt hängen - dachte ich zumindest...
Ich wüsste nicht, wieso. [...]
siehe obigen Link
Au mann, ich hoffe immer noch das Problem irgendwie lösen zu können. Der andere Thread mit mehr oder weniger demselben Problem macht mir da auch net grad viel Hoffnung.
Danke erstmal,
Johanna
Hallo,
Gut, das beweist, dass dieses Verhalten proprietär ist.
Mathias
Hallo,
Gut, das beweist, dass dieses Verhalten proprietär ist.
Und du meinst da ist wirklich gar nichts zu machen??? Irgendwie ist die Lösung doch zum Greifen nahe: das einzige was gemacht werden muss ist doch eval("function test() { alert('TEST'); }"); am window Objekt bzw. im globalen Kontext / Scope oder wie auch immer man das nennen mag, auszuwerten. Das dumme ist halt, dass ich mich dabei zwangsläufig in einer Funktion befinde...
Aber da müsste es doch programmatisch ne Lösung geben, Mann o mann!!! :-)
Danke nochmals, Mathias.
Johanna
Gut, das beweist, dass dieses Verhalten proprietär ist.
Jetzt muss ich nochmal nerven, sorry. Ich bin der Meinung, dass das IE Verhalten doch nicht ganz korrekt ist. Und zwar steht im MSDN dass eval eine Methode des Global Object ist, als window, oder? Weiter steht darüber:
"An intrinsic object whose purpose is to collect global methods into one object. The Global object has no syntax. You call its methods directly. The Global object is never used directly, and cannot be created using the new operator. It is created when the scripting engine is initialized, thus making its methods and properties available immediately." (http://msdn2.microsoft.com/en-us/library/52f50e9t.aspx)
Über eval steht u.a. folgendes drin: "The code passed to the eval method is executed in the same context as the call to the eval method." (http://msdn2.microsoft.com/en-us/library/12k71sw7.aspx)
Das selbe steht übrigens hier: "The scope of eval code is identical to the scope of the calling code." (http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Predefined_Functions:eval_Function)
Daraus folgere ich:
Siehst das immer noch anders, wenn ja warum?
Vielleicht findest du ja nochmal die Zeit.
Danke, Johanna
- da "code passed to the eval method is executed in the same context as the call to the eval method." sollte doch auch mein Aufruf das gewünschte Ergebnis liefern - siehe FF.
Das versteht anscheind MS anders.
function runScript(code)
{
eval(code);
alert('window.test - >' + window.test + '\n' +
'test - >' + test);
};
runScript (" function test () { alert('TEST'); }");
Das entspricht:
function runCode(code)
{
function test () { alert('TEST'); }
alert('window.test - >' + window.test + '\n' +
'test - >' + test);
};
und bei mir verhält sich FF in dem Fall genauso wie der IE.
Struppi.
und bei mir verhält sich FF in dem Fall genauso wie der IE.
In dem Fall wird "test()" vom IE/FF als private Funktion des runScript-Objektes angelegt (NICHT wie Mathias vermutete als globale Funktion) und ist von onclick somit nicht aufzurufen, richtig?
In folgendem Fall verhalten sich IE und FF wie erwartet anders. FF hängt "test" an window an, IE nicht!!! Ich könnte heulen!!!!!
function runScript(code)
{
window.eval(code);
alert('window.test -> ' + window.test + '\n' +
'test -> ' + test);
};
runScript ("function test() { alert('TEST'); }");
Hast du noch ne Idee??? Bin am verzweifeln!
Und kann mir jemand erklären warum das im IE und im FF klappt??? Macht doch dann keinen Sinn! AAAAAAAHHHH!
function runScript(code)
{
eval(code);
alert('window.test -> ' + window.test + '\n' +
'test -> ' + test);
};
runScript ("test = function () { alert('TEST'); }");
Und kann mir jemand erklären warum das im IE und im FF klappt???
Ok ok, ist ne globale Variable - hatten wir schon. Au mann, bin ich jetzt am Arsch!
Hallo,
Daraus folgere ich:
- eval ist immer vorhanden
- eval hängt am globalen Objekt, also an window
- deshalb lässt IE auch window.eval(...) zu, während er document.getElementById('xy').eval(...) nicht mag
Sehe ich auch so.
- da "code passed to the eval method is executed in the same context as the call to the eval method." sollte doch auch mein Aufruf das gewünschte Ergebnis liefern - siehe FF.
Vielleicht verstehst du den Begriff »context« falsch.
Ob ich (an derselben Stelle) eval() oder window.eval() schreibe, das hat keine Auswirkungen auf den Kontext. Der Kontext ist die Umgebung, in der ich das eine oder andere notiere. Entweder der Kontext ist global, außerhalb jeder Funktion, oder er ist lokal, innerhalb einer Funktion.
function func () {
// lokaler Kontext
eval("...");
// Hier rufe ich eval auf. Der Kontext ist der eben dieser Funktion. Sprich, der mit eval ausgeführte Code hat Zugriff auf die lokalen Variablen.
window.eval("...");
// Ist nichts anderes als eine direktere, ausführliche Schreibweise des ersten eval-Aufrufs, bei der nicht nach einer lokalen Variable namens eval gesucht wird. Der Kontext ist hier ebenfalls der durch die Funktion func erzeugte.
}
Dass abweichende Verhalten von Gecko lässt sich m.M.n. nicht aus JavaScript 1.5 bzw. ECMAScript herauslesen und ist offenbar auch nicht dokumentiert.
Mathias
Ich bin K.O. - wie Axel Schulz gestern. Habs nun mit folgendem versucht, da ich dachte, wenn ich beide Strings innerhalb des selben Objekts evaluiere bringts was. Diese Theorie hätte funktioniert, wenn eval('XYZ') immer gleich XYZ (an der selben stelle geschrieben) wäre - so wie ich das bei Struppi vorher verstanden hab. Dem ist aber nicht so. Mein Versuch:
<a href="#" id="xy" onclick="js(onclick_code);">click me</a>
<script type="text/javascript">
function attach(id, handler, code, script)
{
var xy = document.getElementById(id);
xy[handler + "_code"] = code;
if (!xy.js) {
xy.js = function (x) { alert("JS"); eval(x); alert(test); }
}
xy.js(script);
};
attach("xy", "onclick", "test()", "function test() { alert('TEST'); }");
// HIER SIEHT MANS: ALLES TRANSIENT!!!!
// document.getElementById('xy').js();
</script>
Kommentiert man die letzte Zeile aus, sieht man warums nicht funktioniert. Die Evaluierung des Funktionsstring (wenn er exakt so geschrieben ist) ist komplett transient.
***HEUL***
Danke euch trotzdem.
Johanna
Nochmal ein Indiz für das Verhalten von eval():
http://ajaxpatterns.org/On-Demand_Javascript#XMLHttpRequest-Based_On-Demand_Javascript