Mudder: Variablen in temporären Funktionen

Ich möchte in eine temporäre Funktion "Arbeits"-Variablen übergeben. Die Frage ist nur wie.

Als Beispiel

for(var i=0;i<10;i++) {
  element[i].onclick = function() {
    internevariable = i;
    alert(internevariable);
  }
}

Das Problem ist das die Variable i nicht zum Zeitpunkt der Funktionsdefinition übergeben wird sondern erst beim Funktionsaufruf - was entsprechend immer 9 ergeben würde.

Wie also kann ich die Variable i mit dem Wert der Schleife (0, 1, 2, ..) in die temporäre Funktion übertragen?

  1. Hallo Mudder

    keine Ahnung, vielleicht so?
    for(var i=0;i<10;i++) {
      element[i].onclick = function(i) {
        internevariable = this.arguments[i];
        alert(internevariable);
      }
    }

    Moment, besser so ...?

    keine Ahnung, vielleicht so?
    for(var i=0;i<10;i++) {
      element[i].onclick = function() {
        doAlert(i);
      }
    }

    function doAlert( value ){
     alert(value);
    }

    Bernd

    1. Nein beides nicht.
      Temporären Funktionen kann man keine Argumente übergeben und deine zweite Variante hat das selbe Problem wie mein Beispiel vorher, nämlich das bei doAlert trotzdem das aktuelle i und nicht das Schleifen-i übergeben wird.

    2. keine Ahnung, vielleicht so?

      Nein!

      for(var i=0;i<10;i++) {
        element[i].onclick = function(i) {

      Der erste Parameter der onclick Funktion ist in vielen Browsern das Eventobjekt, auch wenn du es i benennst.

      Moment, besser so ...?

      Das ist das gleiche wie im Orginalposting und funktioniert nicht richtig.

      Struppi.

  2. Ich möchte in eine temporäre Funktion "Arbeits"-Variablen übergeben. Die Frage ist nur wie.

    Das nennt sich closure und ist eine anonyme Funktion.

    Als Beispiel

    for(var i=0;i<10;i++) {
      element[i].onclick = function() {
        internevariable = i;
        alert(internevariable);
      }
    }

    Das Problem ist das die Variable i nicht zum Zeitpunkt der Funktionsdefinition übergeben wird sondern erst beim Funktionsaufruf - was entsprechend immer 9 ergeben würde.

    Es gibt zwei Möglichkeiten entweder du erzeugst jedesmal eine neue Funktion (dafür gibt es auch mehrere Möglichkeiten) oder du gibst die Eigenschaft deinem Objekt als Eigenschaft mit.

    Wozu benötigst du das i?

    Struppi.

    1. Ich brauche das für meine AJAX-Anwendung, damit diese mehrere AJAX-Anfragen bearbeiten kann.

      Wenn ich mit einer httpObject-Variable arbeite dann wird diese überschrieben sobald der User die nächste Aktion ausführen will (ehe die alte abgeschlossen ist). So erhält die Parser-Funktion nur die Antwort der zweiten Anfrage, nicht aber die der ersten.

      Naja und das wollte ich eben mit einem Array lösen, wo ich die httpObject's drin speicher und der parser-Funktion den count des korrekten httpObject übergebe. Der wird wiederum durch onreadystatechange aufgerufen und kann (bzw. soll) mit dem übergebenen count das korrekte Objekt herausziehen.

      1. Wenn ich mit einer httpObject-Variable arbeite dann wird diese überschrieben sobald der User die nächste Aktion ausführen will (ehe die alte abgeschlossen ist). So erhält die Parser-Funktion nur die Antwort der zweiten Anfrage, nicht aber die der ersten.

        Dann benutzt du ein globales Objekt, das solltest du vermeiden, anstatt irgendwelche Workarounds zu verwenden. z.b. in dem du bei jeder Anfrage ein neues Objekt erzeugst.

        Struppi.

        1. Ich habe doch geschrieben warum ich mehrere verwenden MUSS. Ich muss mit der AJAX-Anwendung mehrere An/Abfragen parallel bearbeiten können. Und genau das geht eben nicht wenn mir nur ein Objekt zur Verfügung steht.

          1. Ich habe doch geschrieben warum ich mehrere verwenden MUSS. Ich muss mit der AJAX-Anwendung mehrere An/Abfragen parallel bearbeiten können. Und genau das geht eben nicht wenn mir nur ein Objekt zur Verfügung steht.

            Nein, genau das ist das Problem. Wieso stellst du nur ein Objekt zu Verfügung?

            Struppi.

            1. Hä? Das ist doch das selbe!
              Ob ich das Objekt in einer Variable speichere oder in mehreren Variablen. Es bleibt dabei die Tatsache das die Funktionen wissen müssen welches Objekt sie ausführen dürfen und welches nicht. Und da ändert das nix wenn ich sage i (für den Array-Value) oder "variable1" für den Variablennamen.

              1. Hä? Das ist doch das selbe!
                Ob ich das Objekt in einer Variable speichere oder in mehreren Variablen. Es bleibt dabei die Tatsache das die Funktionen wissen müssen welches Objekt sie ausführen dürfen und welches nicht. Und da ändert das nix wenn ich sage i (für den Array-Value) oder "variable1" für den Variablennamen.

                Du brauchst nicht keine Variabel wenn du ein Objekt nimmst, z.b. so:

                function myReq(url, func) {  
                   var http_request = false;  
                   var callback = null;  
                   var ready = function() {  
                      if (http_request.readyState == 4)  {  
                         if(callback) callback( http_request );  
                         return;  
                      }  
                   };  
                   function makeRequest() {  
                      if (window.XMLHttpRequest)  http_request = new XMLHttpRequest();  
                      else if (window.ActiveXObject) http_request = new ActiveXObject("Microsoft.XMLHTTP");  
                      http_request.onreadystatechange = ready;  
                   }  
                  
                   this.load = function(url, func) {  
                      callback = func;  
                      if(!http_request) makeRequest(url);  
                      http_request.open('GET', url, true);  
                      http_request.send(null);  
                   };  
                   if(url) this.load(url, func);  
                }
                

                und dann kannst du ohne Variabeln mehrere Request ausführen:

                new myReq('ajax1.html', function(res) { meineFunktion(res);});  
                new myReq('ajax2.html', function(res) { meineFunktion(res);});  
                new myReq('ajax3.html', function(res) { meineFunktion(res);});  
                
                

                Struppi.

                1. Ok Danke. Ich habe das ganze zwar noch etwas umgebaut doch für dieses Script funktioniert es. Die Verarbeitung der übergebenen Funktion (func) ist damit aber leider nicht so ohne weiteres möglich.

                  Dafür fällt mir aber auch noch was sein.

                  Danke

            2. Edit geht ja leider nicht:
              Im zweiten Satz meinte ich: Ob ich das Objekt in einem Array speichere oder in mehreren Variablen.

  3. Hallo Mudder,

    for(var i=0;i<10;i++) {
      element[i].onclick = function() {
        internevariable = i;
        alert(internevariable);
      }
    }

    hier ist internevariable eine globale Variable, der nacheinander die werte 1 bis 9 zugewiesen werden. Am Ende hat sie den Wert 9. Du musst dafür sorgen, dass internevariable eine lokale Variable wird. Dieses geht mit so genannten closures: du schließt die Variable in eine Funktion ein:

      
     for(var i=0;i<element.length;i++) {  
      ( function(){  
       var internevariable = i;  
       element[i].onclick = function() {  
        alert(internevariable);  
       }  
      })();  
     }
    

    dabei ist

    ( function(){ ... })();

    eine anonyme Funktion, die sofort ausgeführt wird. Die lokalen Variablen in dieser Funktion werden bei den Schleifendurchläufen nicht mehr überschrieben.

    Gruß, Jürgen

    1. eine anonyme Funktion, die sofort ausgeführt wird. Die lokalen Variablen in dieser Funktion werden bei den Schleifendurchläufen nicht mehr überschrieben.

      Hast du das mal probiert?

      Struppi.

      1. Hallo Struppi,

        Hast du das mal probiert?

        Ja, im IE und im FF:

          
        window.onload=function() {  
         var element = document.getElementsByTagName("span");  
          
         for(var i=0;i<element.length;i++) {  
          ( function(){  
           var internevariable = i;  
           element[i].onclick = function() {  
            alert(internevariable);  
           }  
          })();  
         }  
        }
        

        und im body einige <span>s.

        Gruß, Jürgen

        1. Hast du das mal probiert?

          Frage an mich: Hast du dir das Posting von Jürgen genau angeschaut.

          Nein. Ich hab die anonyme Funktion trotz deines Hinweis übersehen, mein Fehler.

          Das war die Umsetzung meines Vorschlags (jedesmal eine neue Funktion zu erzeugen)

          Ich bevorzuge ja eine andere Schreibweise um deutlich zu machen das dies eine Factory ist:

          function createFunc (p) {  
          return function() {alert(p);};  
          };  
          for(var i=0;i<element.length;i++) {  
          element[i].onclick = createFunc(i);  
          }  
          
          

          Aber das ist natürlich Geschmackssache.

          Struppi.

          1. Hallo Struppi,

            Aber das ist natürlich Geschmackssache.

            ich wollte ja auch nur mal zeigen, dass ich

            (function(){ ... })();

            kenne. :)

            Gruß, Jürgen

          2. Hallo,

            function createFunc (p) {

            return function() {alert(p);};
            };
            for(var i=0;i<element.length;i++) {
            element[i].onclick = createFunc(i);
            }

              
            Wenn man das weiter abstrahiert, kommt [bind()](http://aktuell.de.selfhtml.org/artikel/javascript/organisation/#alternativen-kontext) heraus...  
              
            elem.onevent = handler.bind(elem, arg1, arg2, arg3, ...);  
              
            Mathias
            
            -- 
            [SELFHTML aktuell Weblog](http://aktuell.de.selfhtml.org/weblog/)