Kermit: Javascript Funktion später einbinden

Hi,

ich lade per ajax javascript-code in der Seite nach. Dies wird mit eval zu der Zeitpunkt ausgeführt.

Globale Variable werden korrekt initialisiert. Die nachgeladene Funktion wird aber in der HTML Seite nicht gefunden.

Wo wird diese "spätere" Funktion im DOM Baum eingebunden?
Wie kann ich auf diese Funktion zugreifen?

Gruß
Kermit

  1. Lieber Kermit,

    Wo wird diese "spätere" Funktion im DOM Baum eingebunden?
    Wie kann ich auf diese Funktion zugreifen?

    in den DOM-Baum wird die Funktion ganz bestimmt nicht eingebunden, denn es ist kein (X)HTML-Element. Du kannst aber den JS-Code mittels eines <script>-Elements in den <head> des DOMs einbinden. Damit sollte die Funktion dann genauso verfügbar sein, als hättest Du sie von vornherein als <script>-Element im HTML-Dokument stehen gehabt.

    Sollte das von mir Geschriebene jetzt nicht auf Deine Situation zutreffen, dann liegt das daran, dass Du kein noch so winziges Bisschen Code gepostet hast, das "lade per ajax javascript-code in der Seite nach" näher erläutert. Dass Du eval() benutzt, scheint mir nicht sinnvoll zu sein. Aber ohne Code-Beispiel ist da nicht näher zu helfen!

    Liebe Grüße aus Ellwangen,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
    1. Hallo Felix,

      siehe mein Komentar ... da ist ein Beispiel drin
      Ich führe einen eval(...) auf das per ajax übertragene <script> Teil.
      Variablen werden korrekt in den <head> des DOMs eingebunden. Nur die Funktion nicht.

      Lösung 1 wäre die Funktion von Anfang an hochzuladen. Genau das will ich nicht sondern erst später beim event.

      Gruß
      Kermit

      1. Lieber Kermit,

        Du hast mein Posting wohl nur zur Hälfte gelesen, was?

        eval() ist evil! Benutze es nicht! Binde stattdessen das per AJAX erhaltene Script-Element in den <head> Deiner Seite ein. Dann sollte es genau so funktionieren, als ob es schon von vorneherein geladen worden wäre.

        Ich kann mir aber eine Lösung zu Deinem Problem nach Deiner Art vorstellen. Definiere Deine Funktion im nachgeladenen Script doch einmal mit dieser Syntax:
        var TestFunc = function () { };

        Liebe Grüße aus Ellwangen,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
        1. Hallo,

          eval() ist evil! Benutze es nicht!

          Warum?!

          Binde stattdessen das per AJAX erhaltene Script-Element in den <head> Deiner Seite ein. Dann sollte es genau so funktionieren, als ob es schon von vorneherein geladen worden wäre.

          Ist eine Möglichkeit, wenn auch krass umständlich.

          Entweder holt man sich
          JavaScript-Code mit XMLHttpRequest, dann braucht man kein script-Element, sondern eval(). Da ist eval() nicht evil, sondern sinnvoll.

          Oder man bindet ein externes Script mit einem script-Element ein (<script type="text/javascript" src="..."></script>). Kein XMLHttpRequest, kein eval().

          Mathias

          1. Hallo,

            eval() ist evil! Benutze es nicht!

            Warum?!

            Es erzeugt angeblich viel Overhead und kann unsicher sein. Den Spruch "eval is evil" hat meines Wissens Douglas Crockford (YAHOO) geprägt.

            Zitat Douglas: "The eval function is very fast. However, it can compile and execute any JavaScript program, so there can be security issues. The use of eval is indicated when the source is trusted and competent. [...] There are cases where the source is not trusted. In particular, clients should never be trusted."

            Gruß, Don P

            1. Hallo,

              Zitat Douglas: "The eval function is very fast. However, it can compile and execute any JavaScript program, so there can be security issues. The use of eval is indicated when the source is trusted and competent. [...] There are cases where the source is not trusted. In particular, clients should never be trusted."

              Genau: »The use of eval is indicated when the source is trusted and competent.« Also von wegen eval is evil.

              Mathias

              1. Hallo,

                Genau: »The use of eval is indicated when the source is trusted and competent.« Also von wegen eval is evil.

                Naja, an der zitierten Stelle (es geht um JSON) ist Crockford noch ziemlich gnädig mit eval(). Aber ansonsten schreibt und sagt er mehrfach "eval is evil. Don´t use it."

                In einem Vortrag betont er ausdrücklich, dass man eval() nie benutzen soll, außer für JSON, wo es wohl nicht anders geht. Falls man aber irgenwann das Gefühl habe, es doch einsetzen zu wollen, dann solle man ihn einfach anrufen, er werde es einem dann wieder ausreden :-)).

                Da Crockford insgesamt einen äußerst kompetenten Eindruck macht, ist man einfach geneigt, ihm "eval is evil" einfach zu glauben. Da geht es mir nicht anders.

                Die Übertragung per AJAX ist ja genau so ein Anwendungsfall von JSON, also kann man da wohl eval() auch benutzen, wenn man der Quelle vertraut, versteht sich.

                Gruß, Don P

                1. Hallo,

                  Nochmal: Ich wüsste nicht, warum eval() an der hier diskutierten Stelle problematisch ist. Und eine Alternative zum Nachladen von Code habe ich auch genannt. Sie funktionieren allerdings unterschiedlich, haben Vor- und Nachteile, weshalb sie nicht immer durcheinander ersetzbar sind. Felix' starre Ablehnung von eval() halte ich für unbegründet und völlig allgemeine Dogmata sind m.M.n. unbrauchbar, auch wenn sie von einer Autorität stammen.

                  eval() ist meistens einfach unnötig und wird benutzt, wenn die elegantere und JavaScript-typische Lösungsweise unbekannt ist. Wenn ich Code nachladen will, existieren wie gesagt im Groben nur zwei Alternativen, von der ich i.d.R. das Einbinden eines script-Elements präferieren würde. Damit ist auch JSONP möglich, eine Möglichkeit, JSON-Daten ohne XMLHttpRequest kontrolliert nachzuladen. Und die Same Origin Policy wirkt nicht, was u.a. JSONP-Web-Services möglich macht.

                  Mathias

                  1. Hallo,

                    Nochmal: Ich wüsste nicht, warum eval() an der hier diskutierten Stelle problematisch ist.

                    Ich auch nicht wirklich. Felix schrieb genau, was Crockford meistens sagt, und du fragtest, warum. Ich denke, eben gerade weil Crockford es sagt. Die Frage ist eigentlich, warum genau bringt Crockford das so plakativ (s.u.)?

                    Und eine Alternative zum Nachladen von Code habe ich auch genannt.

                    Ist klar. Es gibt Alternativen.

                    Felix' starre Ablehnung von eval() halte ich für unbegründet und völlig allgemeine Dogmata sind m.M.n. unbrauchbar, auch wenn sie von einer Autorität stammen.

                    Da wäre ich mir nicht so sicher. Das Problem ist, dass wenn man "eval is evil" genau begründet, damit automatisch auch eine Anleitung zum Missbrauch gegeben wird. Sicher ist, dass es dabei um Sicherheitsrisiken geht, und wenn man nicht gerade eine Hackeranleitung schreiben will, muss man sich eben auf Aussagen wie "eval is evil. Don´t use it!" beschränken.

                    eval() ist meistens einfach unnötig und wird benutzt, wenn die elegantere und JavaScript-typische Lösungsweise unbekannt ist.

                    Das stimmt, ist aber m.E. kein hinreichender Grund zur Verteufelung von eval(). Crockford empfiehlt z.B. auch, auf das with-Statement komplett zu verzichten, ohne aber zu sagen, with sei böse. Es führt nur zu manchmal uneindeutigem Code. "evil" meint aber mehr als nur "unnötig, es geht auch anders", es meint wirklich "böse, schädlich".

                    [...] nur zwei Alternativen, von der ich i.d.R. das Einbinden eines script-Elements präferieren würde. [...] Und die Same Origin Policy wirkt nicht [...].

                    Das ist leider auch ein Sicherheitsrisiko. Zum dynamischen Nachladen via script-Tag, dem sogenannten "Script Tag Hack", meint Crockford: "[...] is not secure and should be avoided."
                    Seinem Link folgend findet man dann in roter Schrift "Be extremely cautious in your own use, and even more cautious in teaching it outside. The unrestricted script tag hack is the last big security hole in browsers. It cannot be easily fixed because the whole advertising infrastructure depends on the hole. Be very cautious." (Dieses Zitat ist nicht von Crockford)

                    Man fragt sich natürlich, was dann überhaupt noch als sicher angesehen werden kann, wenn man JavaScript einsetzt. Ich habe dazu einmal einen Thread eröffnet, und der Tenor der Antworten war sinngemäß "kein Problem, alles im grünen Bereich". Naja, kommt wohl darauf an, welchen Anspruch man bzgl. Sicherheit hat...

                    Gruß, Don P

  2. Hallo,

    Globale Variable werden korrekt initialisiert. Die nachgeladene Funktion wird aber in der HTML Seite nicht gefunden.

    Wo wird diese "spätere" Funktion im DOM Baum eingebunden?

    eval() führt Code, sofern du es nicht anders angibst, im globalen Scope aus. Wenn du da auf oberster Ebene function () {} stehen hast, dann wird ein Funktionsobjekt beim globalen Objekt, dem aktuellen window-Objekt erzeugt.
    Solche Funktionen sind nichts anderes als »globale Variablen«, insofern glaube ich das nicht recht...

    Wie kann ich auf diese Funktion zugreifen?

    Wie üblich:
    funktion();
    alert(funktion);

    Mathias

    1. Hallo Mathias,

      wie soll ich die neue Funktion in der Seite bekannt machen?
      ins Detail zum nachvollziehen sieht es so aus:

      ------------------- client-rechner -------------------
      <a href="#" onClick="alert('var1='+var1);">Link1</a>
      <a href="#" onClick="testFunc('b');">Link2</a>
      1. am anfang funktionieren beide Links nicht (Fehler:"not defined")

      2. event auslösen (onClick) und ajax_request bearbeiten...
      anschliessend nach neuer script suchen und ausführen:
      eval($(sId).getElementsByTagName('script')[0].innerHTML);

      3. ein alert wird angezeigt mit "testFunc wurde aufgerufen mit:a"
      innerhalb der script section, während eval ausgeführt wird, ist testFunc bekannt

      4. klick auf Link "Link1" -> alert "var1=1"
      var1 ist in der Seite bekannt

      5. klick auf Link "Link2" -> javascript Fehler: "testFunc not defined"
      anscheint ist testFunc was anderes als »globale Variablen«
      wieso?

      --------------- wird per ajax vom server geladen --------------
      <div id="ajax_script">
      <script...
      var1 = 1;
      var2 = 2;

      function testFunc(sParam) {
         alert('testFunc wurde aufgerufen mit:'+sParam);
         return true;
      }

      testFunc('a');
      </script>
      </div>

      --------------------------------------------------------------

      1. Hallo,

        anschliessend nach neuer script suchen und ausführen:
        eval($(sId).getElementsByTagName('script')[0].innerHTML);

        Wieso machst du das so?

        Du montierst ein script-Element ein, hängst den Code als Textknoten an und führt den dann mit eval() aus?

        Wieso arbeitest du nicht direkt XMLHttpRequest.responseText? Was hat es mit dem script-Element auf sich?

        1. ein alert wird angezeigt mit "testFunc wurde aufgerufen mit:a"

        Wo wird der alert aufgerufen?

        innerhalb der script section, während eval ausgeführt wird, ist testFunc bekannt

        Ok, also wird der Code ausgeführt. Fehlerfrei?

        1. klick auf Link "Link2" -> javascript Fehler: "testFunc not defined"
          anscheint ist testFunc was anderes als »globale Variablen«

        Steht der eval() in einer Funktion?

        Dann liegt es daran, dass du die Funktionen als lokale Variablen definierst. Beispiel:

          
        function f () {  
         eval("function a () {}");  
         // ist dasselbe wie hier direkt function a () {} zu schreiben  
         // und das ist identisch damit hier vier a = function () {}; zu schreiben  
         // und das legt bekanntlich eine LOKALE Variable an, d.h.  
         // die Funktion ist nur hier in der Funktion f verfügbar, nicht global  
        }  
        f();  
        alert(typeof window.a); // gibts nicht  
        
        

        Ok, was macht man da? Zum Beispiel die Funktion ausdrücklich beim window-Objekt speichern:

          
        function f () {  
         eval("window.a = function () {};");  
        }  
        f();  
        alert(typeof window.a); // ok  
        a(); // geht  
        
        

        --------------- wird per ajax vom server geladen --------------
        <div id="ajax_script">
        <script...

        Siehe oben. Das ist so eigentlich überflüssig, warum nicht direkt JavaScript-Code zurückgeben?

        Mathias

    2. Hallo,

      eval() führt Code, sofern du es nicht anders angibst, im globalen Scope aus.

      Stimmt nicht... Wenn man eval("function f () {}"); in einer Funktion ausführt, wird keine globale Funktion angelegt.

      Mathias