L. Denver Mint: OOP: Instanzname auslesen

Hi!

Ich bin grade auf der Suche nach einer Moeglichkeit den Instanznamen eines Objektes auszulesen. Aber weiss jetzt nach meiner bisherigen Suche immernoch nicht ob das ueberhaupt irgendwie moeglich ist.
Ich hab dazu etwas in einem englischsprachigen Forum gefunden, wo auch ein Link zu einer Webseite gepostet wurde, die sich mit "Closures" befasst. Fuer einen Loesungsansatz werden diese offenbar verwendet. (http://jibbering.com/faq/faq_notes/closures.html)

Ich verstehe diese Quelle nur nicht so recht. Das Thema ist fuer mich scheinbar neu und recht komplex, so dass das verstaendnis durch zusaetzliche sprachliche maengel nicht unbedingt besser wird. Ich wollte deshalb mal hier anfragen, ob es auch gut verstaendliche deutsche quellen zu dem Thema gibt!?

Danke fuer eure Hilfe
L. Denver Mint

  1. Hallo L.,

    Was ist der Instanzname? So etwas existiert eigentlich höchstens intern z.B. in Form einer Speicheradresse.
    Du solltest genauer erklären, was Du meinst. Gibt vielleicht etwas Beispielcode an, wo ein solcher Instanzname vor kommt und wo Du den herausfinden willst.

    Dieser Artikel handelt von OO und wie lokale Variablen behandelt werden.
    Eine Closure ist dabei sowas:

    function erzeugeFunk(param) {
      return new function() {
        return param;
      }
    }

    var bla = erzeugeFunk("hallo");
    alert(bla());

    Dabei sieht man einerseits das Funktionen auch nur spezielle Objekte sind und man sie daher auch zurückgeben kann und Referenzen darauf existieren können.
    Außerdem sieht man, dass der Parameter param, der ja eigentlich nur lokal in erzeugeFunk gilt, dadurch weiter existiert, dass man ihn in der zurückgegebenen Funktion verwendet.

    Grüße

    Daniel

  2. Hallo,
    Ich habe mir in JavaScript inzwischen angewöhnt, im Objekt-Konstruktor IMMER den Namen der Variablen anzugeben, weil ich den Instanznamen oft für Sachen wie z.B. window.setTimeout (aufgerufen aus der Klasse selbst) brauche.

    function meine_klasse (id, param1, param2) {
        this.id = id;
        this.param1 = param1;
        this.param2 = param2;
        this.doStuff = doStuff;

    window.setTimeout(this.id+".doStuff();", 200);

    }

    function doStuff () {
       // mach irgendwas
    }

    var Instanz = new meine_klasse("Instanz", "a", "b");

    Nicht besonders schön, und ein Dorn im Auge eines OO-Programmierers,  aber effektiv :)

    Viele Grüße,
    Jörg

    Nicht besonders schön, aber

    1. Hallo Jörg,

      Ich würde ja diese Variante bevorzugen:

      function MeineKlasse() {
        this.doStuff = function() {
          alert(1);
        };
        window.setTimeout(this.doStuff, 5000);
      }

      var bla = new MeineKlasse();

      Wobei ein Konstruktor eher keine solchen Seiteneffekte haben sollte.
      Opera und Geckos können das, ob der IE das auch kann, weiß ich nicht.

      (In meinem vorherigen Posting habe ich new vor function beim Erzeugen einer annonymen Funktion geschrieben, das ist natürlich falsch)

      Grüße

      Daniel

      1. Hallo,

        window.setTimeout(this.doStuff, 5000);

        Wieder was gelernt. Ich wusste gar nicht, dass der erste Parameter von window.setTimeout auch eine Funktion sein kann....dachte bislang immer, das muesste zwingend ein String sein.

        Joerg

        1. Wieder was gelernt. Ich wusste gar nicht, dass der erste Parameter von window.setTimeout auch eine Funktion sein kann....dachte bislang immer, das muesste zwingend ein String sein.

          Ah. Der MacIE und IE5.0 kanns nicht, der  braucht einen String - ich wusste doch, irgendein Haken muss dabei gewesen sein =)

          Joerg

      2. Hallo,

        function MeineKlasse() {
          this.doStuff = function() {
            alert(1);
          };
          window.setTimeout(this.doStuff, 5000);
        }

        var bla = new MeineKlasse();

        Wobei ein Konstruktor eher keine solchen Seiteneffekte haben sollte.

        Der Punkt ist m.E. vielmehr: Warum dann noch ein eigenes Objekt verwenden? Das Übergeben der Funktion an setTimeout reißt sie vollkommen aus ihrem Objektkontext. Der Zugriff auf Eigenschaften und Methoden der Instanz ist dann nicht mehr möglich. this verweist auf window, nicht auf die Instanz, diese ist nur über ihren Namen ansprechbar. Das verlangt eine umständliche Lösung, daher ist Jörgs Version letztlich vorteilhafter, denn sie belässt die Methode in ihrem Kontext und führt sie regulär aus.
        Ebenso umständlich wäre das Übergeben der Instanz an die aus dem Kontext gerissene Funktion:

        function Prototyp () {  
          this.eigenschaft = "hallo";  
          this.methode1 = function () { alert(this.eigenschaft); };  
          this.methode2 = function (objekt) { alert(objekt.eigenschaft + " " + objekt.methode1); };  
          window.setTimeout(this.methode2, 1000, this);  
        }  
        var instanz = new Prototyp();
        

        Erlaubt ebenfalls nur Zugriff auf öffentliche Eigenschaften und Methoden, wird aber nur von wenigen Browsern unterstützt.

        Mathias

        1. Hallo molily,

          Gut, man muss ja keine Methode des Objekts nehmen. Man könnte auch sowas schreiben:

          function Klasse() {
            this.tueWas();
            var instanz = this;
            window.setTimeout(function() {
              instanz.tueWas();
            }, 1000);
          }

          Der Vorteil davon ist, dass man keine globalen Referenzen auf alle Objekte braucht, die irgendwie Timeouts verwenden. Außerdem muss das Objekt nicht den Kontext kennen, in dem es referenziert wird. So etwas kann sich ja auch immer wieder ändern. Ein bezug auf eine globale Referenz aus dem Objekt selbst heraus schafft da eine ansonsten unnötige Abhängigkeit.

          Selbst wenn sich das Objekt nicht selbst registriert, ist es sinnvoller, eine Funktion zu übergeben um sich globale Referenzen zu spaaren. Man hat auch viel mehr Möglichkeiten Informationen aus dem Kontext in dieser Funktion zu verwenden. Andernfalls müsste man diese auch global verfügbar machen oder in den String codieren.

          Grüße

          Daniel

          1. Hallo,

            function Klasse() {
              this.tueWas();
              var instanz = this;
              window.setTimeout(function() {
                instanz.tueWas();
              }, 1000);
            }

            Die Variable "instanz" hast Du aber in dem Moment nicht mehr, wo Du den window.setTimeout verlässt. Da window-setTimeout ja event gesteuert ist und nicht wie ein "sleep" oder "wait" arbeitet (also nicht wirklich die Prozessausführung anhält), wird nach dem window.setTimeout die Funktion Klasse verlassen. Der Stack wird abgeräumt, nach einer Sekunde triggert der Eventhandler, will "instanz.tueWas()" aufrufen, was nicht mehr geht, weil das Objekt instanz nicht mehr existiert.

            "instanz" müsste folglicch global sein, womit wir aber wieder die störende Abhängigkeit haben, die Du angesprochen hast.

            Grüße,
            Jörg

            1. Die Variable "instanz" hast Du aber in dem Moment nicht mehr, wo Du den window.setTimeout verlässt. Da window-setTimeout ja event gesteuert ist und nicht wie ein "sleep" oder "wait" arbeitet (also nicht wirklich die Prozessausführung anhält), wird nach dem window.setTimeout die Funktion Klasse verlassen. Der Stack wird abgeräumt, nach einer Sekunde triggert der Eventhandler, will "instanz.tueWas()" aufrufen, was nicht mehr geht, weil das Objekt instanz nicht mehr existiert.

              Das stimmt so nicht.

              "instanz" müsste folglicch global sein, womit wir aber wieder die störende Abhängigkeit haben, die Du angesprochen hast.

              nein, durch var ist es lokal aber bleibt bei der lokalen Funktionserzeugung erhalten.

                
              <script type="text/javascript">  
              function Klasse(n, t) {  
                this.name = n;  
                this.t = t;  
                
                var instanz = this;  
                window.setTimeout(function() {  
                  instanz.tu_was();  
                }, t);  
              }  
                
              Klasse.prototype.tu_was = function()  
              {  
                 alert(this.name + ' nach ' + this.t + 'ms');  
              }  
                
              var o1 = new Klasse('A', 4000);  
              var o2 = new Klasse('B', 1000);  
                
              </script>  
              
              

              Wobei man aber sagen muss das geht nicht in allen Browsern. Aber in llen aktuellen

              Struppi.

            2. Hallo Jörg,

              In JavaScript lebt diese Variable tatsächlich weiter.
              Die Variable wird beim Verlassen der Funktion wohl vom Stack genommen, wenn sie noch benötigt werden oder Variablen liegen gar nicht auf dem Stack, sondern lediglich Referenzen darauf.
              Es geht z.B. auch sowas:

                
              function test() {  
                var wert = "a";  
                var result = new Object();  
                result.setze = function() {  
                  wert = "b";  
                };  
                result.zeige = function() {  
                  alert(wert);  
                };  
                return result;  
              }  
              var t = test();  
              t.zeige();  
              t.setze();  
              t.zeige(); //b wird ausgegeben.  
              
              

              Grüße

              Daniel

              1. In JavaScript lebt diese Variable tatsächlich weiter.

                Eigentlich auch logisch, denn....

                Die Variable wird beim Verlassen der Funktion wohl vom Stack genommen, wenn sie noch benötigt werden oder Variablen liegen gar nicht auf dem Stack, sondern lediglich Referenzen darauf.

                .. die Funktion wird ja nicht in dem Sinne verlassen oder aufgerufen. Du erzeugst ein neus Objekt test, mit der privaten Variabel result, diese bleibt solange erhalten, solange das Objekt vorhanden ist.

                Struppi.

                1. Hallo Struppi,

                  Nein, tue ich nicht. Evtl. hast Du da ein "new" gelesen, wo keine stand.
                  Die Funktion test() wird einfach nur aufgerufen. Ich erzeuge eine neues Objekt um mehrere Werte damit zurückzugeben.
                  Aber auch darauf kann ich natürlich verzichten:

                    
                  var zeige;  
                  var setze;  
                  function test() {  
                    var wert = "a";  
                    setze = function() {  
                      wert = "b";  
                    };  
                    zeige = function() {  
                      alert(wert);  
                    };  
                  }  
                  test();  
                  zeige();  
                  setze();  
                  zeige();  
                  
                  

                  Der Kontext in dem die beiden inneren Funktionen deklariert werden, bleibt also erhalten. Wie auch immer das genau Implementiert ist, es ist eine Funktionalität, die sich nicht automatisch aus den OO-Eigenschaften von JavaScript ergibt.

                  Grüße

                  Daniel

                  1. Nein, tue ich nicht. Evtl. hast Du da ein "new" gelesen, wo keine stand.

                    Du hast recht.

                    Der Kontext in dem die beiden inneren Funktionen deklariert werden, bleibt also erhalten. Wie auch immer das genau Implementiert ist, es ist eine Funktionalität, die sich nicht automatisch aus den OO-Eigenschaften von JavaScript ergibt.

                    Interessant, werd ich mich auch mal bei Gelegenheit mit beschäftigen, was dahinter steckt. Oder einer unserer Experten hier bringt ein wenig Licht in diese sache.

                    Struppi.

                    1. Hallo,

                      Der Punkt ist einfach:
                      Wenn man irgendwo eine Funktion definiert, sei es per Deklaration, Expression oder über den Function-Konstruktor, gibt es zwei Scopes: Der Scope der Umgebung der Funktion und der Scope der Funktion selbst. Eine so notierte Funktion hat immer Zugriff auf den umgebenden Scope. Mit dem Funktionsobjekt kann man danach anstellen, was man will, es an andere Objekte heften, es als Parameter weitergeben usw. Der Scope bleibt erhalten. Ein paar Beispiele:

                      <script type="text/javascript">
                      // globaler Scope
                      var g = "g ";
                      function a () {
                        // globaler Scope + Scope der Funktion a
                        var eA = "a ";
                        (function b () {
                          // globaler Scope + Scope der Funktionen a + b
                          var eB = "b ";
                          (function c () {
                            // globaler Scope + Scope der Funktionen a + b + c
                            var eC = "c ";
                            function d (kontext) {
                              // globaler Scope + Scope der Funktionen a + b + c + d + Scope des Objekts, dessen Methode sie ist
                              var eD = "d ";
                              alert("this: " + this + "\nkontext: " + kontext + "\n" +
                                g + eA + eB + eC + eD + (typeof(this.eF) == "string" ? this.eF : "")
                              );
                            }
                            d("c()");
                            e = d;
                            call(d);
                            constr.prototype.func = d;
                          })();
                        })();
                      }
                      function call (func) {
                        func("call()");
                      }
                      function constr () {
                        this.eF = "e";
                        this.func("constr()");
                      }
                      a();
                      var obj = new constr();
                      e("global");
                      obj.func("global obj.func()");
                      </script>

                      Mathias