Jörg Peschke: Speicherplatz von "Methoden" in JavaScript

Hallo zusammen,
Ich befasse mich zur Zeit ein bisschen mit ActionScript-Programmierung...ist ja recht ähnlich zu JavaScript.

Beim Studium der Action Script Coding Standards bin ich auf Folgendes gestossen:

"When Creating objects, attach object functions and properties that will be shared across all instances of the object to the prototype of the object. This ensures that only one copy of each function exists in memory. As a general rule, do not define functions within the constructor. This creates a copy of the same function for each object instance and unnecessarily wastes memory..."

Jetzt frage ich mich: Ist das in JavaScript genauso?
Generell halte ich nämlich die Definition von Methoden im Konstruktor für sinnvoller, als erst ein Objekt zu bauen, dem ich dann per Prototype wieder umständlich eine Funktion unterschieben muss
(es sei denn natürlich, ich will genau das tun, z.b. um Vererbung zu emulieren oder so etwas).

Wer weiß mehr darüber?

  1. Hi there,

    Jetzt frage ich mich: Ist das in JavaScript genauso?

    Könnte browserabhängig sein...

  2. Hallo,

    "When Creating objects, attach object functions and properties that will be shared across all instances of the object to the prototype of the object. This ensures that only one copy of each function exists in memory. As a general rule, do not define functions within the constructor. This creates a copy of the same function for each object instance and unnecessarily wastes memory..."

    Jetzt frage ich mich: Ist das in JavaScript genauso?

    Soweit ich weiß ja, ich habe das schon einmal gelesen in Bezug auf JavaScript.

    Allerdings weiß ich nicht, ob JavaScript-Interpreter da nicht sowieso optimieren. Was offensichtlich immer wieder neue Funktionsobjekte erzeugt:

    function Konstruktor () {
       this.methode = function () { ... };
    }

    Folgendes müsste aber nur eine Referenz anlegen:

    function methode () { ... }
    function Konstruktor () {
       this.methode = methode;
    }

    Allerdings muss man sich hier natürlich im Klaren sein, dass methode im zweiten Fall keinen Zugriff auf die privaten Eigenschaften des Objektes hat, weil keine Closure vorliegt.

    Mit
    Konstruktor.prototype.methode = function () { ... };
    ist man wohl tatsächlich auf der sicheren Seite, denn beim Erzeugen von Instanzen wird soweit ich weiß eine Referenz angelegt. Aber diese Methode ist ebenfalls nicht priviligiert.

    Die Frage für mich ist eher, ob man sich über solche Performancefragen in JavaScript Gedanken machen muss. Ich fand die IE-Memory-Leaks schon vernachlässigbar. Dieses Problem kommt wahrscheinlich erst zum tragen, wenn man tausende Objekte mit richtig vielen Eigenschaften und Methoden hat.

    Generell halte ich nämlich die Definition von Methoden im Konstruktor für sinnvoller, als erst ein Objekt zu bauen, dem ich dann per Prototype wieder umständlich eine Funktion unterschieben muss

    Wieso ist das umständlich? Man hat den Vorteil, dass man im Konstruktor wirklich nur die Initialisierung vornehmen kann und Eigenschaften und Methoden ausgelagert über die prototype-Eigenschaft hinzugefügt werden.

    Mathias

    1. Moin,
      Danke für Deine Antwort.

      Wieso ist das umständlich? Man hat den Vorteil, dass man im Konstruktor wirklich nur die Initialisierung vornehmen kann und Eigenschaften und Methoden ausgelagert über die prototype-Eigenschaft hinzugefügt werden.

      Hm, für mich hat das zwei Gründe:
      1.) Optisch: Ich habe das im Quellcode gerne gekappselt:
      "Klasse" (wenn man das in JavaScript so nenen darf :) )

      function meineKlasse ()
      {
          //Eigenschaften
          //Methoden
      }

      Man sieht dann sofort, dass diese Methoden wirklich zu dieser Klasse gehören, ähnlich wie's in Java o.ä. auch ist.

      2.) Logisch
      Eine normale Methode gehört in meinen Augen zur Klassendefintion.
      Wenn ich etwas schreibe wie:

      var meineInstanz = new MeinObjekt();

      erwarte ich danach, dass "meineInstanz" alles kann, was "MeinObjekt" können soll.

      Wenn ich die Methoden erst danach hinzufüge:

      var meineInstanz = new MeinObjekt();
      meineInstanz.prototype.methode1 = function () {...}
      meineInstanz.prototype.methode2 = function () {...}

      ist "meineInstanz" zum Zeitpunkt der Erzeugung noch "nackt".

      -> finde ich "unschön" (auch wenns technisch natürlich keinen großen Unterschied macht).

      Grüße,
      Jörg

      1. Hallo,

        Wenn ich die Methoden erst danach hinzufüge:
        ist "meineInstanz" zum Zeitpunkt der Erzeugung noch "nackt".

        Wieso sollte man auch so vorgehen, das ist m.E. nicht die gängige Praxis und auch nicht nötig. Üblicherweise werden die »Klassen«-Definitionen zentral ausgelagert, die Instantiierung erfolgt erst danach. Natürlich kann man jederzeit ausgehend von einer Instanz prototypische Erweiterungen vornehmen, aber der Sinn von OOP ist gerade diese Trennung auf Codebasis.

        • Formale Deklaration
          -- Konstruktorfunktion definieren.
          -- Eigenschaften und Methoden dem Konstruktor prototypisch hinzufügen.

        • Konkrete Instantiierung mit gewissen Parametern/Eigenschaften

          
        function K () { ... }  
        K.prototype = {  
         methode : function () {  
          alert("Hallo Welt!");  
         }  
         /* und weitere Eigenschaften/Methoden */  
        };  
          
        /* an anderer Stelle: */  
        var instanz = new K;  
        instanz.methode();  
        
        

        Mathias

        1. Hallo molily,

          function K () { ... }
          K.prototype = {
          methode : function () {
            alert("Hallo Welt!");
          }

          Wenn man sowas macht, müsste doch bei jedem Konstruktoraufruf der Prototyp ausgetauscht werden?

          Ich würde an der Stelle wirklich sagen, dass es Aufgabe eines Interpreters ist, die Funktionen an dieser Stelle nicht vollständig mehrfach anzulegen, d.h. zumindest den Code bzw. ein daraus erzeugter Bytecode oder was auch immer der Interpreter damit macht nur einmal im Speicher zu halten.

          Den Funktionskontext muss man natürlich mehrmals anlegen, da er sich unterscheiden kann (z.B. wegen lokaler Variablen des Konstruktors) und auch später vermutlich geändert werden kann.
          Welche Eigenschaften hat denn eine Javascript-Funktion, die man später noch ändern kann?

          Grüße

          Daniel

          1. Hallo,

            function K () { ... }
            K.prototype = {
            methode : function () {
              alert("Hallo Welt!");
            }
            };
            Wenn man sowas macht, müsste doch bei jedem Konstruktoraufruf der Prototyp ausgetauscht werden?

            Hmm, nein, wieso? Die Zuweisung steht doch nicht in der Konstruktorfunktion. Oder verstehe ich dich falsch?

            Mathias

            1. Hallo molily,

              Hmm, nein, wieso? Die Zuweisung steht doch nicht in der Konstruktorfunktion.

              Du hast recht. Ich hab' die Klammern falsch zugeordnet.

              Grüße

              Daniel

        2. Hallo,

          Üblicherweise werden die »Klassen«-Definitionen zentral ausgelagert, die Instantiierung erfolgt erst danach. Natürlich kann man jederzeit ausgehend von einer Instanz prototypische Erweiterungen vornehmen, aber der Sinn von OOP ist gerade diese Trennung auf Codebasis.

          Das kommt darauf an - in Java z.b. schreibst Du alle Methoden direkt in die Klasse. Es sei denn, du nimmst Interfaces ein.
          Auch in PHP stehen alle Methoden in der Klasse selbst.

          function K () { ... }
          K.prototype = {
          methode : function () {
            alert("Hallo Welt!");
          }
          /* und weitere Eigenschaften/Methoden */
          };

          Möglicherweise verstehe ich die Prototype-Eigenschaft nicht richtig, aber nach meinem bisherigen Verständnis greift das Prototype-Objekt auf erzeugende Klasse zu.  
          In Deinem Beispiel würde (nach meinem Verständnis) daher die Methode "methode" dem "function" - Objekt zugeweisen.  
            
          Denn gewissermaßen ist ja K eine Instanz der Klasse "function".  
          In Actionscript benutzt man genau diesen Effekt um allen Filmen im Projekt ein bisschen mehr "Können" zu verleihen:  
            
          MovieClip.prototype.methode = function () {...}  
            
          Ab hier beherrschen alle MovieClips die Methode "methode".  
            
          Dein Obiges Beispiel funktioniert natürlich trotzdem, denn  
          K ist als Instanz von function natürlich in der Lage, sämtliche Methoden von "function" (und somit auch "methode") auszuführen.  
            
          Nur können dann alle anderen von "function" abgeleiteten Objekte ebenfalls "methode" ausführen - was ja unter Umständen nicht im Sinne des Erfinders ist (weil man z.b. abhängig von der Objekt-Klasse jeweils eine unterschiedliche "methode" implementieren will).  
            
          Oder bin ich mit meinem Verständnis von "prototype" komplett auf dem Holzweg?  
            
            
          Grüsse,  
          Jörg  
            
            
          
          
          1. Korrektur, Molily hatte doch recht, hab das gerade nochmal nachgeschlagen:
            http://www.javascriptkit.com/javatutors/proto2.shtml.

            Ist also doch ein gangbarer weg, wie er von Molily vorgeschlagen wurde.

            Viele Grüße,
            Jörg

          2. Hallo,

            Möglicherweise verstehe ich die Prototype-Eigenschaft nicht richtig, aber nach meinem bisherigen Verständnis greift das Prototype-Objekt auf erzeugende Klasse zu.

            Nein. Da es keine Klassen gibt, sondern nur Konstruktoren, ersetzen wir mal das Wort durch Konstruktur. »Das Prototyp-Objekt greift auf den erzeugenden Konstruktor zu«. Das ist nicht richtig - genau das leistet die constructor-Eigenschaft.

            irgendeineFunktion.constructor === Function
            irgendeineFunktion.prototype === das Prototyp-Objekt eben dieser Funktion, hat mit Function erstmal nichts zu tun, höchstens dass es mit dessen Prototyp in einer vererbenden Prototyp-Kette steht

            In Deinem Beispiel würde (nach meinem Verständnis) daher die Methode "methode" dem "function" - Objekt zugeweisen.

            Nein, prototype ist einfach nur eine Eigenschaft von allen Funktionsobjekten. Darin ist ein Objekt gespeichert, also eine Liste von anderen, benannten Objekten.

            Instantiiert man nun die Funktion mit »new«, benutzt sie also als Konstruktor, werden alle Member dieses Prototyp-Objektes in die neue Instanz (und alle anderen schon bestehenden Instanzen) herüberkopiert (bzw. referenziert). Das ist alles.

            MovieClip.prototype.methode = function () {...}

            Ab hier beherrschen alle MovieClips die Methode "methode".

            Genau, alle Objekten mit dem Konstruktor MovieClip.

            Denn gewissermaßen ist ja K eine Instanz der Klasse "function".
            Dein Obiges Beispiel funktioniert natürlich trotzdem, denn K ist als Instanz von function natürlich in der Lage, sämtliche Methoden von "function" (und somit auch "methode") auszuführen.

            Ich habe aber nirgendwo den Prototyp von Function erweitert, sondern nur den Prototyp von K. Wenn ich dem Konstruktor Function irgendetwas anhänge, hat das noch längst keine Wirkung auf alle Funktionen. Function.neueMethode = function () {}; fügt eben nur diesem Konstruktor eine Methode hinzu. Will ich allen Funktionsobjekten eine Methode ankleben, muss ich über den Prototyp gehen: Function.prototype.neueMethode.

            Nur können dann alle anderen von "function" abgeleiteten Objekte ebenfalls "methode" ausführen - was ja unter Umständen nicht im Sinne des Erfinders ist (weil man z.b. abhängig von der Objekt-Klasse jeweils eine unterschiedliche "methode" implementieren will).

            Nein. bestimmtesFunktionsobjekt.prototype.neueMethode ist etwas anderes als bestimmtesFunktionsobjekt.constructor.prototype.neueMethode bzw., was dasselbe ist, Function.prototype.neueMethode.

            Mathias

      2. Hallo,

        var meineInstanz = new MeinObjekt();
        meineInstanz.prototype.methode1 = function () {...}

        Äh, das geht ja auch gar nicht. Eine prototype-Eigenschaft hat nicht die Instanz, sondern deren Konstruktor. Will man nachträglich alle Instanzen erweitern, müsste es meineInstanz.constructor.prototype heißen, das wäre dann identisch zu MeinObjekt.prototype.

        Mathias

      3. Hi

        um das ganzes optisch besser zu strukturieren mache ich meine "Klassen" so (genannt "dynamsiches Prototyping"):

          
        function meineKlasse(a,b,c)  
        {  
            this.a = a;  
            this.b = b;  
            this.c = c;  
          
            if(typeof meineKlasse._initialized == "undefined")  
            {  
                meineKlasse.prototype.meineMethode = function(test)  
                {  
                     alert(test);  
                };  
          
                meineKlasse._initialized = true;  
            }  
        }  
        
        

        ist imho mit die eleganteste Art.
        Das ganze habe ich aus dem Buch Professional JavaScript for Web Developers - das ich nur wärmstens empfehlen kann (ist halt englisch). Dort werden auch noch andere Möglichkeiten zur Klassen-/Objektdefinition aufgelistet und deren evtl vorhandene Probleme erklärt. Natürlich ist das nur ein Kapitel von dem Buch :P

        Grüße

        Bezkeroon

        1. um das ganzes optisch besser zu strukturieren mache ich meine "Klassen" so (genannt "dynamsiches Prototyping"):

          function meineKlasse(a,b,c)
          {
              this.a = a;
              this.b = b;
              this.c = c;

          if(typeof meineKlasse._initialized == "undefined")
              {
                  meineKlasse.prototype.meineMethode = function(test)
                  {
                       alert(test);
                  };

          meineKlasse._initialized = true;
              }
          }

            
          Wozu soll das gut sein?  
            
          Struppi.
          
          -- 
          [Javascript ist toll](http://javascript.jstruebig.de/) (Perl auch!)
          
          1. Wozu soll das gut sein?

            Struppi.

            na das ganzes ist optisch besser Strukturiert, steht doch da.

            Man hat die gesamte Definition der Klasse in einem Block und durch die Abfrage ob _initialized definiert ist, werden die Funktionen (sind auch Objekte) auch nur ein einziges mal erzeugt. Das Gleiche erreicht man natürlich auch, wenn man die Funktionen per prototype außerhalb des eigentlichen Klassenblocks definiert. Nur genau das finden halt einige Verwirrend (wie auch der Eröffner des Threads), weil die Klasse verteilt ist und man nicht sofort sieht, welche Methoden zu ihr gehören

            1. na das ganzes ist optisch besser Strukturiert, steht doch da.

              Naja.

              Man hat die gesamte Definition der Klasse in einem Block und durch die Abfrage ob _initialized definiert ist, werden die Funktionen (sind auch Objekte) auch nur ein einziges mal erzeugt. Das Gleiche erreicht man natürlich auch, wenn man die Funktionen per prototype außerhalb des eigentlichen Klassenblocks definiert. Nur genau das finden halt einige Verwirrend (wie auch der Eröffner des Threads), weil die Klasse verteilt ist und man nicht sofort sieht, welche Methoden zu ihr gehören

              Das ist Quatsch, der Prototype wird nur einmal deklariert, der normale Weg den auch Mathias schon erläutert hat, geht so:

                
              function meineKlasse(a,b,c)  
              {  
                   this.a = a;  
                   this.b = b;  
                   this.c = c;  
              }  
              meineKlasse.prototype =  
              {  
              meineMethode: function(test)  
              {  
              alert(test);  
              }  
              }  
              
              

              Die prototype Funktionen stehen ausserhalb und werden nur einmal deklariert. Das die prototype deklaration innerhalb der contructor Funktion stehen hab ich noch nie gesehen.

              Struppi.

              --
              Javascript ist toll (Perl auch!)
              1. Man hat die gesamte Definition der Klasse in einem Block und durch die Abfrage ob _initialized definiert ist, werden die Funktionen (sind auch Objekte) auch nur ein einziges mal erzeugt. Das Gleiche erreicht man natürlich auch, wenn man die Funktionen per prototype außerhalb des eigentlichen Klassenblocks definiert. Nur genau das finden halt einige Verwirrend (wie auch der Eröffner des Threads), weil die Klasse verteilt ist und man nicht sofort sieht, welche Methoden zu ihr gehören

                Das ist Quatsch, der Prototype wird nur einmal deklariert, der normale Weg den auch Mathias schon erläutert hat, geht so:

                äh ja - hast schon gelesen, was ich geschrieben hab? ;)

                hier nochmal:

                Das Gleiche erreicht man natürlich auch, wenn man die Funktionen per prototype außerhalb des eigentlichen Klassenblocks definiert.

                Wenn man die Funktionen aber innerhalb des Klassenblocks definieren will (und genau um das gings imho in dem Beitrag, auf den ich geantwortet habe) werden die bei jeden Instanziierung neu angelegt

                1. Wenn man die Funktionen aber innerhalb des Klassenblocks definieren will (und genau um das gings imho in dem Beitrag, auf den ich geantwortet habe) werden die bei jeden Instanziierung neu angelegt

                  wirklich?
                  Das glaube ich nicht.

                  Struppi.

                  --
                  Javascript ist toll (Perl auch!)
                  1. Wenn man die Funktionen aber innerhalb des Klassenblocks definieren will (und genau um das gings imho in dem Beitrag, auf den ich geantwortet habe) werden die bei jeden Instanziierung neu angelegt

                    wirklich?
                    Das glaube ich nicht.

                    Struppi.

                    wenn Du das so definierst:

                    nn

                    wird bei folgendem code die Funktion 'methode' 2x erzeugt - der code wird ja auch 2mal durchlaufen.
                    klasse1 = new klasse();
                    klasse2 = new klasse();

                    um das zu verhindern (und trotzdem alles in einem Block zu haben) hab ich mein obiges Beispiel gepostet.

                    Grüße

                    Bezkeroon

                    1. wird bei folgendem code die Funktion 'methode' 2x erzeugt - der code wird ja auch 2mal durchlaufen.
                      klasse1 = new klasse();
                      klasse2 = new klasse();

                      wie hast du das festgestellt?
                      Meine Festellung ist eine andere.

                      Struppi.

                      --
                      Javascript ist toll (Perl auch!)
                2. Wenn man die Funktionen aber innerhalb des Klassenblocks definieren will (und genau um das gings imho in dem Beitrag, auf den ich geantwortet habe) werden die bei jeden Instanziierung neu angelegt

                  und hier noch die Kontrolle:

                    
                  function Obj()  
                  {  
                     Obj.prototype.func = function() {   };  
                     this.func_2 = function() {   };  
                  }  
                  var a1 = new Obj();  
                  var a2 = new Obj();  
                    
                  alert(  
                  ( a1.func === a2.func)  
                  + "\n" +  
                  ( a1.func_2 === a2.func_2)  
                  )  
                  
                  

                  Deshalb ist es Blödsinn die Deklaaration innerhalb des Konstruktor zu machen aber es schadet nichts.

                  Der Denkfehler ist, dass hier etwas nacheinander abläuft. Das ist aber nicht so, denn ein Skript wird nur einmal übersetzt, dabei stößt der Übersetzer auf [Objekt].prototype und diese wird dann intern nicht innerhalb der Funktion ausgeführt, sondern einmal an das Objekt gebunden. Das heißt vom Standpunkt des Javascript übersetzters ist diese Deklaration nicht innerhalb irgendeines Block.

                  Den prototype innerhalb des constructor zu definieren hat aber dann den Vorteil das man auf private Variabeln zugreifen kann.

                  Struppi.

                  --
                  Javascript ist toll (Perl auch!)
                  1. a1.func === a2.func

                    gibt true, das stimmt.

                    aber der Ablauf is ja folgender

                    mit var a1 = new Obj(); wird ein neues Objekt instanziiert und der prototype von Obj wird mit einer leeren Funktion überschrieben.
                    bei var a2 = new Obj(); passiert nochmal das gleiche.

                    Da der prototype aber für a1 und a2 gleich ist gibt das logischerweise auch true aus. Das ändert aber nichts daran, dass 'func' 2x definiert wird. Nur geht halt der Zeiger bei beiden Instanzen auf das gleiche Objekt (Funktion).

                    Evtl reden wir auch aneinander vorbei - ich sagte man braucht, wenn man das ganze prototyping im Kontruktor machen will, eine Variable, die sicherstellt, dass das ganze nur einmal stattfindet und ned bei jeder Instanziierung von Neuem.

                    Grüße

                    Bezkeroon

                    1. aber der Ablauf is ja folgender

                      mit var a1 = new Obj(); wird ein neues Objekt instanziiert und der prototype von Obj wird mit einer leeren Funktion überschrieben.
                      bei var a2 = new Obj(); passiert nochmal das gleiche.

                      nein, das ist nicht der Ablauf.

                      1. wird das Obj erzeugt inkl. seiner Prototypen.
                      2. Beim aufruf von new() wird dann Speicherplatz dafür reserviert. die Prototype Funktionen sind aber schon längst übersetzt.

                      Da der prototype aber für a1 und a2 gleich ist gibt das logischerweise auch true aus. Das ändert aber nichts daran, dass 'func' 2x definiert wird. Nur geht halt der Zeiger bei beiden Instanzen auf das gleiche Objekt (Funktion).

                      Nein, func ist nur einmal vorhanden dass beweist auch der Vergleich.

                      Evtl reden wir auch aneinander vorbei - ich sagte man braucht, wenn man das ganze prototyping im Kontruktor machen will, eine Variable, die sicherstellt, dass das ganze nur einmal stattfindet und ned bei jeder Instanziierung von Neuem.

                      Und das stimmt nicht.

                      Struppi.

                      --
                      Javascript ist toll (Perl auch!)
                      1. Hi,

                        ich bin anderer Meinung (die btw auch durch das von mir weiter oben Verlinkte Buch untermauert wird!), aber der Diskussion auch schon überdrüssig.

                        Also belassen wirs einfach dabei -_-

                        Grüße

                        Bezkeroon

                        1. ich bin anderer Meinung (die btw auch durch das von mir weiter oben Verlinkte Buch untermauert wird!), aber der Diskussion auch schon überdrüssig.

                          Das Buch irrt (wie nicht selten im Bereich JS).

                          Also belassen wirs einfach dabei -_-

                          Klar, ich hab den Beweis ja dargelegt.

                          Prototypen werden nicht zur Laufzeit neuangelegt, sondern einmal zur Übersetzungszeit, im gegensatz zu den "inline" Funktionen. Es spielt also für'S Übersetzungsverhalten keine Rolle, ob du einen Prototyp in oder ausserhalb des Konstruktors plazierst.

                          Struppi.

                          --
                          Javascript ist toll (Perl auch!)
                          1. ich kanns doch nicht lassen.

                            Wenn die Prototypen ja nur EINMAL zur Übersetzungszeit angelegt werden, wieso geht dann folgendes:

                            function klasse()
                                {
                                    klasse.prototype.func = function() { alert("Funktion 1"); } ;
                                }

                            a = new klasse();
                                a.func();
                                neu = prompt("Neuen Prototyp eingeben", "");
                                eval(neu);
                                a.func();

                            beim Prompt gib jetzt einfach mal
                                klasse.prototype.func = function() { alert("Funktion 2"); } ;
                            ein

                            Es geht also sehr wohl zur Laufzeit - also wird auch, wie ich geschrieben hab 2x eine Funktion angelegt, wenn ein Prototyp im Kontruktor vorhanden ist und diese Klasse 2x instanziiert wird.

                            Du behauptest ja mittlerweile schon, dass

                            function klasse()
                                {
                                    klasse.prototype.func = function() { alert("Funktion 1"); } ;
                                }

                            technisch das gleiche sei wie

                            function klasse()
                                {}
                                klasse.prototype.func = function() { alert("Funktion 1"); } ;

                            oder täusche ich mich?

                            Grüße

                            Bezkeroon

                            1. Wenn die Prototypen ja nur EINMAL zur Übersetzungszeit angelegt werden, wieso geht dann folgendes:

                              Weil eval ein Übersetzungprozess ist.

                              Es geht also sehr wohl zur Laufzeit - also wird auch, wie ich geschrieben hab 2x eine Funktion angelegt, wenn ein Prototyp im Kontruktor vorhanden ist und diese Klasse 2x instanziiert wird.

                              Wie gesagt eval ist ein Übersetzungsprozess während der Laufzeit. Das erklärt aber nicht, warum die Prototypfunktionen absolut identisch sind, während Funktionen die mit this erzeugt werden unterschiedlich sind.

                              Du behauptest ja mittlerweile schon, dass

                              function klasse()
                                  {
                                      klasse.prototype.func = function() { alert("Funktion 1"); } ;
                                  }

                              technisch das gleiche sei wie

                              function klasse()
                                  {}
                                  klasse.prototype.func = function() { alert("Funktion 1"); } ;

                              oder täusche ich mich?

                              Hab ich auch nicht behauptet, ich sagte ich hätte das noch nie gesehen. Der zweite Weg ist der übliche den ich bisher überall so gesehen habe.

                              Technisch ist aber das Erste eine priviligierte Prototyp Funktion das zweite nicht, was zumindest eine Erweiterung meines Wissens ist.

                              Was aber zu gehen scheint ist das die Übersetzung verhindert wird, was mir neu war. Nur, wenn einmal ein protoyp erzeugt wurde ist es immer der gleiche.

                                
                              function klasse(c)  
                              {  
                                  if(c == 1) klasse.prototype.func = function() { alert("Funktion 1"); } ;  
                                  if(c == 2) klasse.prototype.func = function() { alert("Funktion 2"); } ;  
                              }  
                                
                              var a0 = new klasse(0);  
                              alert( typeof a0.func ) // undefined  
                              var a1 = new klasse(1);  
                              a1.func(); // Funktion 1  
                              var a2 = new klasse(2);  
                              a2.func(); // Funktion 2  
                                
                              a1.func(); // Funktion 2  
                              a0.func(); // Funktion 2  
                              
                              

                              Struppi.

                              --
                              Javascript ist toll (Perl auch!)
                              1. so, jetzt mein letztes Posting, dann geb ich's auf -_-

                                eine Funktion, die über prototype definiert wurde ist in jeder Instanz des zugehörigen Objekts als _Referenz_ vorhanden.

                                genau diese Referenzen können aber sehr wohl zur Laufzeit überschrieben werden bzw die Referenz zeigt dann halt auf ein neues Objekt - für ALLE Instanzen!

                                wenn also das Objekt so definiert ist:

                                function Obj()
                                {
                                    Obj.prototype.func = function () {};
                                }

                                dann wird mit jeder Instanz dieses Objekts auch ein neues Objekt für die prototype-Funktion angelegt. Die Referenz auf die Funktion wird allerdings für alle Instanzen geändert - die erste erstellte Funktion per prototype landet also irgendwo im Speichernirvana.

                                Da Du mir ja leider partou nicht glauben willst, hab ich hier jetzt nochmal was für Dich, was beweist, dass ich Recht habe:

                                function Obj()
                                {
                                    Obj.prototype.func = function () { };
                                    this.funktion = this.func;
                                }

                                a = new Obj();
                                alert(a.func === a.funktion);  //ergibt true
                                b = new Obj();
                                alert(a.func === a.funktion);  //ergibt false
                                alert(b.func === a.func);      //ergibt true

                                Grüße

                                Bezkeroon

                                P.S.: Einen richtigen "Übersetzungprozess" gibt es im übrigen im JavaScript nicht wirklich, aber das nur nebenbei :P

                                1. eine Funktion, die über prototype definiert wurde ist in jeder Instanz des zugehörigen Objekts als _Referenz_ vorhanden.

                                  Ja, wird aber nicht jedesmal neu angelegt, wie dein erstes Posting suggeriert.

                                  genau diese Referenzen können aber sehr wohl zur Laufzeit überschrieben werden bzw die Referenz zeigt dann halt auf ein neues Objekt - für ALLE Instanzen!

                                  Hab ich nie bestritten, und dass es für alle Instanzen gilt, ist das was ich die ganze Zeit sage.

                                  wenn also das Objekt so definiert ist:

                                  function Obj()
                                  {
                                      Obj.prototype.func = function () {};
                                  }

                                  dann wird mit jeder Instanz dieses Objekts auch ein neues Objekt für die prototype-Funktion angelegt. Die Referenz auf die Funktion wird allerdings für alle Instanzen geändert - die erste erstellte Funktion per prototype landet also irgendwo im Speichernirvana.

                                  Die ist an das Objekt gebunden, d.h. alle Objekte greifen auf diese Funktion zu. Intern wird das in etwa so umgesetzt, dass die Funktion func() mit dem Objekt zu dem es gehört als Parameter aufgerufen wird.

                                  Da Du mir ja leider partou nicht glauben willst, hab ich hier jetzt nochmal was für Dich, was beweist, dass ich Recht habe:

                                  Das Beispiel entspricht dem was ich die ganze Zeit versuche dir zu erklären. Das eine prototype Funktion nur einmal übersetzt wird und danach für alle Objekte zu Verfügung steht. Das also dein Konstrukt relativ überflüssig ist.

                                  P.S.: Einen richtigen "Übersetzungprozess" gibt es im übrigen im JavaScript nicht wirklich, aber das nur nebenbei :P

                                  Keine Ahnung was du unter Richtig verstehst, aber Interpretaion ist eine Übersetzung des Codes.

                                  Struppi.

                                  --
                                  Javascript ist toll (Perl auch!)
                  2. Hallo,

                    function Obj()
                    {
                       Obj.prototype.func = function() {   };
                       this.func_2 = function() {   };
                    }
                    var a1 = new Obj();
                    var a2 = new Obj();

                    alert(
                    ( a1.func === a2.func)

                    Was soll das zeigen? Ein Objekt ist mit sich selbst identisch, klar. Beim zweiten Konstruktor-Aufruf werden a1.func und a2.func mit demselben Objekt überschrieben. Ergo sind sie identisch, logisch. Das heißt aber nicht, dass die Zeile nur einmal ausgeführt wird.

                    ein Skript wird nur einmal übersetzt, dabei stößt der Übersetzer auf [Objekt].prototype und diese wird dann intern nicht innerhalb der Funktion ausgeführt, sondern einmal an das Objekt gebunden.

                    Das verstehe ich nicht. Ich kann .prototype.irgendwas beliebig oft während der Laufzeit überschreiben.

                    Das heißt vom Standpunkt des Javascript übersetzters ist diese Deklaration nicht innerhalb irgendeines Block.

                    Doch, sie wird so oft ausgeführt, wie ich den Konstruktor ausführe, wieso auch nicht?

                    Den prototype innerhalb des constructor zu definieren hat aber dann den Vorteil das man auf private Variabeln zugreifen kann.

                    Naja, eigentlich das ein Nachteil, denn es funktioniert nicht so, wie man denkt. Dein Beispiel abgewandelt:

                    function klasse (c) {
                     klasse.prototype.func = function closure () { alert(c); } ;
                    }
                    var a1 = new klasse(1);
                    a1.func();
                    var a2 = new klasse(2);
                    a2.func();
                    a1.func();

                    c ist hier eine private Eigenschaft, durch Closure ist sie in func verfügbar. Aber indem man über prototype geht, ändert man alle func-Methoden von allen Instanzen. Alle Instanzen haben dann eine func, die die Variablen des letzten Konstruktoraufrufs »einschließt«. Sprich, man kann auf die Weise nicht auf die privaten Eigenschaften der jeweiligen Instanz zugreifen.

                    Mathias

                    1. Doch, sie wird so oft ausgeführt, wie ich den Konstruktor ausführe, wieso auch nicht?

                      Mittlerweile hatte ich das auch festgestellt. Ich bin da wohl ein bisschen von Perl ausgegangen, wo solche Sachen auch zur Übersetzungzeit abgearbeitet werden (z.b. use Modul, kann stehen wo es will, es wird immer vor dem ausführen des Codes übersetztz [ausser in einem eval Block natürlich] ).

                      Diese Aussage von mir ist also falsch.

                      Naja, eigentlich das ein Nachteil, denn es funktioniert nicht so, wie man denkt. Dein Beispiel abgewandelt:

                      Das wäre der einzige Grund gewesen die vorgeschlagene Schreibweise zu verwenden, denn sie ist auch langsamer (je nach Browser und Anzahl der prototype Funktionen, zwischen 10-100%)

                      Struppi.

                      --
                      Javascript ist toll (Perl auch!)
  3. Hi,

    Ich befasse mich zur Zeit ein bisschen mit ActionScript-Programmierung...ist ja recht ähnlich zu JavaScript.
    Jetzt frage ich mich: Ist das in JavaScript genauso?

    BTW: Mozillas nächste JS-Engine wird übrigens ohnehin die Script-Engine von Adobe sein. Adobe hat sie explizit deswegen als Open Source zur Verfügung gestellt ...

    Gruß, Cybaer

    --
    Hinweis an Fragesteller: Fremde haben ihre Freizeit geopfert, um Dir zu helfen. Helfe Du auch im Archiv Suchenden: Beende deinen Thread mit einem "Hat geholfen" oder "Hat nicht geholfen"!