wucher wichtel: Verständnisproblem bei OOP mit Javascript

Hallo!

Ich versuche mich gerade in die objektorientierte Programmierung mit Javascript einzuarbeiten. Da habe ich mir mal das Beispiel in SELFHTML angeschaut. Da steht folgender Code:

  
<html><head><title>Test</title>  
<script type="text/javascript">
~~~~~~javascript
  
function Farbe (R, G, B) {  
  this.R = R;  
  this.G = G;  
  this.B = B;  
  this.hex = "#";  
}  
  
function HintergrundWechseln () {  
  var Hintergrund = new Farbe("E0", "FF", "E0");  
  document.bgColor = Hintergrund.hex + Hintergrund.R + Hintergrund.G + Hintergrund.B;  
}
~~~~~~html
  
</script>  
</head><body bgcolor="#FFFFFF">  
<h1>Das eigene Farb-Objekt mit JavaScript</h1>  
<a href="javascript:HintergrundWechseln()">Hintergrundfarbe wechseln</a>  
</body>  
</html>  

Dabei verstehe ich nicht, was Javascript macht wenn zum Beispiel auf die Eigenschaft R des Objekts Farbe(), per Hintergrund.R zugegriffen wird. Wie läuft das ab? Was passiert in dieser Zeile?

  
var Hintergrund = new Farbe("E0", "FF", "E0");  

Sind durch diese Zuweisung die Eigenschaften von Farbe auch die von Hintergrund? Oder sind das zwei verschiedene Paar Stiefel? Wenn ich jetzt die Eigenschaften R,G und B von Farbe ändere, wirkt sich das dann auch auf zum Beispiel Hintergrund.R aus?

Das ist mein erster ernsthafter Schritt in Richtung objektorientiertes Programmieren. Deswegen die vielleicht dummen Fragen :-)

ciao, ww

--
Dies ist eine sehr einfache und effektive Sicherheitsstufe, aber nicht perfekt. Denn wenn mehrere User über eine Leitung ins Internet gehen, haben für den Webserver alle User die selbe IP. Und dann wirkt diese Sicherheitsstufe nicht mehr. Aber zumindest könnt ihr demjenigen, der euch die Session-ID geklaut hat, eins in die Fresse hauen.
http://tut.php-q.net/login.html
  1. hi,

    <html><head><title>Test</title>
    <script type="text/javascript">

      
    
    > function Farbe (R, G, B) {  
    >   this.R = R;  
    >   this.G = G;  
    >   this.B = B;  
    >   this.hex = "#";  
    > }  
    >   
    > Dabei verstehe ich nicht, was Javascript macht wenn zum Beispiel auf die Eigenschaft R des Objekts Farbe(), per Hintergrund.R zugegriffen wird. Wie läuft das ab? Was passiert in dieser Zeile?  
      
    Das Erzeugen einer Objektinstanz mit  
    
    > [code lang=javascript]  
    > var Hintergrund = new Farbe("E0", "FF", "E0");  
    > 
    
    ~~~  
    jetzt die Objekteigenschaften this.R, this, G, this.B auf die übergebenen Werte.  
      
    Da du dir deine Objektinstanz in var Hintergrund abgelegt hast, hast du anschliessend mit Hintergrund.R Zugriff auf diese Objekteigenschaft (weil sie "public", als "öffentlich", von aussen einsehbar, ist).  
      
    
    > Sind durch diese Zuweisung die Eigenschaften von Farbe auch die von Hintergrund?  
      
    Farbe definiert lediglich das Objekt - Hintergrund ist eine konkrete Objektinstanz, die hast du ja mit new Farbe(...) erzeugt.  
      
    
    > Wenn ich jetzt die Eigenschaften R,G und B von Farbe ändere, wirkt sich das dann auch auf zum Beispiel Hintergrund.R aus?  
      
    Die kannst du gar nicht ändern, weil Farbe keine Objektinstanz ist.  
      
    
    > Das ist mein erster ernsthafter Schritt in Richtung objektorientiertes Programmieren. Deswegen die vielleicht dummen Fragen :-)  
      
    <http://aktuell.de.selfhtml.org/artikel/javascript/oomodell/> und  
    <http://aktuell.de.selfhtml.org/artikel/javascript/organisation/>  
    seien dir ans Herz gelegt :-),  
    <http://phrogz.net/JS/Classes/OOPinJS.html> ebenfalls noch.  
      
    gruß,  
    wahsaga  
      
    
    -- 
    /voodoo.css:  
    #GeorgeWBush { position:absolute; bottom:-6ft; }
    
    1. Hallo!

      Danke für die Antwort und für die Links. Ich werde sie durcharbeiten :)

      ciao, ww

      --
      Dies ist eine sehr einfache und effektive Sicherheitsstufe, aber nicht perfekt. Denn wenn mehrere User über eine Leitung ins Internet gehen, haben für den Webserver alle User die selbe IP. Und dann wirkt diese Sicherheitsstufe nicht mehr. Aber zumindest könnt ihr demjenigen, der euch die Session-ID geklaut hat, eins in die Fresse hauen.
      http://tut.php-q.net/login.html
  2. var Hintergrund = new Farbe("E0", "FF", "E0");

    
    > Sind durch diese Zuweisung die Eigenschaften von Farbe auch die von Hintergrund?  
      
    Nein Hintergrund ist ein Objekt vom Typ Farbe.  
      
    
    >  Oder sind das zwei verschiedene Paar Stiefel? Wenn ich jetzt die Eigenschaften R,G und B von Farbe ändere, wirkt sich das dann auch auf zum Beispiel Hintergrund.R aus?  
      
    Du kannst nicht die Eigenschaften von Farbe ändern, das ist lediglich ein Objekt  
      
    Struppi.
    
    -- 
    [Javascript ist toll](http://javascript.jstruebig.de/) (Perl auch!)
    
    1. Hallo!

      Auch an dich. Danke schön!

      ciao, ww

      --
      Dies ist eine sehr einfache und effektive Sicherheitsstufe, aber nicht perfekt. Denn wenn mehrere User über eine Leitung ins Internet gehen, haben für den Webserver alle User die selbe IP. Und dann wirkt diese Sicherheitsstufe nicht mehr. Aber zumindest könnt ihr demjenigen, der euch die Session-ID geklaut hat, eins in die Fresse hauen.
      http://tut.php-q.net/login.html
  3. Hi,

    Was passiert in dieser Zeile?

    var Hintergrund = new Farbe("E0", "FF", "E0");

      
    ändern wir es mal ein bisschen:  
      
    

    function Farbe (R, G, B) {
      this.R = R;
      this.G = G;
      this.B = B;
      this.hex = "#";
      this.toString = function() { return this.hex+this.R+this.G+this.B; }
      return 'Fertig';
    }

      
    Man beachte das "return" in der letzten Zeile - es wird nur für diese Demonstration gebraucht. Nun machen wir den Aufruf:  
    

    alert(new Farbe("E0", "FF", "E0"));
    alert(    Farbe("E0", "FF", "E0"));

      
    Das alert() bewirkt, dass implizit eine toString()-Methode aufgerufen wird, da es nur einen String ausgeben kann.  
      
    Vergleiche die Ergebnisse der beiden Aufrufe. Denke über sie nach - und stelle Deine Rückfragen ;-)  
      
    
    > Sind durch diese Zuweisung die Eigenschaften von Farbe auch die von Hintergrund?  
      
    "Farbe" ist eine Funktion. In diesem Kontext ist es das, was dem aus der OOP bekannten Begriff "Klasse" am nächsten kommt. "Hintergrund" ist eine Instanz der Klasse "Farbe". Die Klasse wird durch die Instanz nicht verändert. Wäre es anders, wäre es nicht objektorientiert.  
      
    
    > Wenn ich jetzt die Eigenschaften R,G und B von Farbe ändere, wirkt sich das dann auch auf zum Beispiel Hintergrund.R aus?  
      
    JavaScript verfolgt das Prototype-Modell, d.h. es gibt in der Tat einen Weg, alle Instanzen (und alle abgeleiteten Klassen) einer Klasse nachträglich zu verändern. Bei dem, was Du beschrieben hast, passiert dies jedoch nicht.  
      
    Cheatah  
    
    -- 
    X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|  
    X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html  
    X-Will-Answer-Email: No  
    X-Please-Search-Archive-First: Absolutely Yes
    
    1. Hallo!

      Danke schön Cheatah. Du hast mich ziemlich zum Nachdenken gebracht :-) Ich hab den Thread schon gar nicht mehr beachtet. Deswegen schreibe ich jetzt erst.

      Das Ergebnis der Alerts überrascht mich :) und vor allem verstehe ich es nicht.

        
      this.toString = function() { return this.hex+this.R+this.G+this.B; }  
      
      

      Wofür braucht man das "this" vor "toString"? toString ist doch keine Methode von Farbe?! Aber jetzt sehe ich, dass im Beispiel von SELFHTML folgendes steht:

        
      var Dezimalzahl = 15.5;  
      var Dualzahl = Dezimalzahl.toString(2);  
      
      

      Was ist an toString so besonders? toString() ist eine Methode des Number-Objekts. write() ist eine Funktion des window-Objekts. Die Methode write() ruft man per document.write() auf. Deswegen müsste man doch eigentlich toString() so aufrufen: number.toString(). Oder? Ich habe irgendwie ziemlich große Probleme mit toString() :-)

      Das 'Fertig' wird beim ersten Mal nicht ausgegeben, weil das Ausführen der Methode wegen dem return in der Zeile davor, schon abgebrochen wurde. Stimmt das? Und warum wird beim Aufruf durch

        
      alert(Farbe("E0", "FF", "E0"));  
      
      

      nicht die Zeile

        
      this.toString = function() { return this.hex+this.R+this.G+this.B; }  
      
      

      ausgeführt? Ok, ich weiß wieso. Weil eben beim Aufruf nicht new Farbe steht. Aber trotzdem habe ich es nicht verstanden. Warum interessiert sich JS nicht für diese Zeile. Ignoriert Javascript auch die folgenden Zeilen?

        
      this.R = R;  
      this.G = G;  
      this.B = B;  
      
      

      Was mich auch verwirrt, aber eigentlich nichts mit OOP zutun hat ist die Methode toString. In SELFHTML heißt es:

      Wandelt eine Zahl in eine Zeichenkette (String) um.

      Es wird aber die Funktion new Farbe() aber mit diesen Parametern aufgerufen: "E0", "FF", "E0". Aber diese Parameter sind zwar Hexzahlen, aber für Javascript sind es doch Strings. Sie werden ja auch in Anführungszeichen übergeben. Also warum braucht man eine Methode, die Zahlen in Strings umwandelt, wenn man schon Strings hat? Irgendwas habe ich falsch verstanden...

      ciao, ww

      --
      Dies ist eine sehr einfache und effektive Sicherheitsstufe, aber nicht perfekt. Denn wenn mehrere User über eine Leitung ins Internet gehen, haben für den Webserver alle User die selbe IP. Und dann wirkt diese Sicherheitsstufe nicht mehr. Aber zumindest könnt ihr demjenigen, der euch die Session-ID geklaut hat, eins in die Fresse hauen.
      http://tut.php-q.net/login.html
      1. hi,

        this.toString = function() { return this.hex+this.R+this.G+this.B; }

        
        > Wofür braucht man das "this" vor "toString"? toString ist doch keine Methode von Farbe?!  
          
        Das this davor braucht man, um toString zu einer privilegierten Methode zu machen, die von ausserhalb aufgerufen werden darf.  
          
        
        > Aber jetzt sehe ich, dass im Beispiel von SELFHTML folgendes steht:  
        >   
        > ~~~javascript
          
        
        > var Dezimalzahl = 15.5;  
        > var Dualzahl = Dezimalzahl.toString(2);  
        > 
        
        

        Was ist an toString so besonders? toString() ist eine Methode des Number-Objekts. write() ist eine Funktion des window-Objekts. Die Methode write() ruft man per document.write() auf. Deswegen müsste man doch eigentlich toString() so aufrufen: number.toString(). Oder?

        Nee, wenn schon Number.toString (Javascript ist case-sensitive).

        Aber du willst ja hier nicht die Methode einer "Klasse" aufrufen, sondern die einer konkreten Klasseninstanz - und die trägt den Namen Dualzahl.
        Also rufst du mit Dualzahl.toString() die Methode dieser Instanz auf - und die gibt dann in diesem Falle den Zahlwert mit zwei Nachkommastellen aus.

        Ich habe irgendwie ziemlich große Probleme mit toString() :-)

        Grundsätzlich wird die toString-Methode immer dann gebraucht, wenn ein Objekt in einem Kontext verwendet wird, der nach einem String verlangt.

        alert("Wert: "+5);

        alert gibt Strings aus, der Operator + für die Stringverkettung wird hier benutzt - und da 5 vom Typ Number ist, wird dessen toString-Methode aufgerufen, um aus 5 einen String zu machen, der sich mit "Wert: " verketten lässt. Sieht in diesem Falle nicht nach großem Tennis aus - passiert aber trotzdem :-)

        Das 'Fertig' wird beim ersten Mal nicht ausgegeben, weil das Ausführen der Methode wegen dem return in der Zeile davor, schon abgebrochen wurde. Stimmt das?

        Nein.
        Wenn du nur Farbe() aufrufst, ist das ein stinknormaler Funktionsaufruf - Funktion läuft durch, und gibt mit return "Fertig" zurück.

        Wenn du aber explizit new Farbe() verwendest, erzeugst du damit eine neue Instanz von Farbe. Rückgabe ist in diesem Falle die erzeugte Objektinstanz.
        Und da _diese_ jetzt als Argument für alert benutzt wird, muss sie in einen String-Kontext gebracht werden - also wird ihre toString-Methode aufgerufen, und die gibt ganz explizit das Ergebnis des Ausdrucks this.hex+this.R+this.G+this.B zurück.

        Kommentiere die Methode mal aus, und rufe dann noch mal
        alert(new Farbe("E0", "FF", "E0"));

        • jetzt erhältst du nur eine Ausgabe [object] o.ä.
          Du hast keine eigene toString-Methode definiert - also wird die benutzt, die Farbe vom allgemeinen Typ Object geerbt hat - denn jede Funktion ist in javascript ja auch ein Object. Nur ist die leider so allgemein, dass sie von Farbe und dessen Eigenschaften nichts weiss - sie hat keine Ahnung, dass ein Objekt vom Typ Farbe die Eigenschaften R, G und B besitzt. Also kann sie auch keine detailiertere Auskunft über diese Objekt vom Typ Farbe geben, als dass es irgendwie vom Typ Object ist - und deshalb gibt sie nur [object] (o.ä., je nach Browser/Implementation ggf. etwas unterschiedlich) zurück, das ist alles, was sie darüber sagen kann.

        Und warum wird beim Aufruf durch

        alert(Farbe("E0", "FF", "E0"));

        
        > nicht die Zeile  
        >   
        > ~~~javascript
          
        
        > this.toString = function() { return this.hex+this.R+this.G+this.B; }  
        > 
        
        

        ausgeführt? Ok, ich weiß wieso. Weil eben beim Aufruf nicht new Farbe steht.

        Weil Farbe hier nur einfach eine Funktion ist, die ausgeführt wird.
        Da wird zwar irgendeiner Eigenschaft eine Funktionsreferenz zugewiesen - aber wen interessiert das in dem Moment? So eine Zuweisung erzeugt nichts "sichtbares" - es ist genau das gleiche, als hättest du irgendwo var foo = 5; notiert - schön, da wird ein Wert zugewiesen, kümmert aber in dem Moment niemanden wirklich.

        Aber trotzdem habe ich es nicht verstanden. Warum interessiert sich JS nicht für diese Zeile. Ignoriert Javascript auch die folgenden Zeilen?

        this.R = R;
        this.G = G;
        this.B = B;

          
        Ignoriert werden sie nicht, während die Funktion abgearbeitet wird, werden da natürlich Zuweisungen gemacht.  
        Aber der Rückgabewert der Funktion ist nur vom Typ String mit dem Inhalt "Fertig".  
        this hat zwar innerhalb der Funktion auf diese gezeigt, die Eigenschaften konnten auch "angelegt" werden - aber du hast keinen Zugriff mehr darauf, weil alles was du zurückbekommst, "Fertig" ist.  
          
        
        > Was mich auch verwirrt, aber eigentlich nichts mit OOP zutun hat ist die Methode [toString](http://de.selfhtml.org/javascript/objekte/number.htm#to_string). In SELFHTML heißt es:  
        > ####  
        > Wandelt eine Zahl in eine Zeichenkette (String) um.  
        > ####  
        > Es wird aber die Funktion new Farbe() aber mit diesen Parametern aufgerufen: "E0", "FF", "E0". Aber diese Parameter sind zwar Hexzahlen, aber für Javascript sind es doch Strings. Sie werden ja auch in Anführungszeichen übergeben. Also warum braucht man eine Methode, die Zahlen in Strings umwandelt, wenn man schon Strings hat?  
          
        Vorsicht, die Stelle auf die du hier verweist, bezieht sich explizit auf das Number-Objekt.  
        Wir haben aber ein selbstdefiniertes Objekt Farbe mit einer eigenen toString-Methode - das hat nicht das geringste mit Number zu tun.  
        Und bei Farbe benutzen wir diese Methode jetzt ja nicht, um Zahlen in irgendwas zu verwandeln - sondern um die Werte der Eigenschaften hex, R, G und B miteinander zu verketten, und das als Ergebnis zurückzugeben - damit liefert uns unser Objekt vom Typ Farbe, welches einzelne (Farb-)Eigenschaften besitzt diese ganz praktisch in einer Form zurück, die wir sofort als Farbdefinition in bspw. Zuweisungen an CSS-Farbeigenschaften verwenden können.  
          
        gruß,  
        wahsaga  
          
        
        -- 
        /voodoo.css:  
        #GeorgeWBush { position:absolute; bottom:-6ft; }
        
        1. Hallo!

          Vielen Dank für die ausführliche Erklärungen. Vieles habe ich jetzt verstanden, allerdings hakt es bei einer Sache noch.

          Kann ich zum Beispiel mit this.write() dafür sorgen, dass etwas geschrieben wird? Kann ich mit dem Schlüsselwort this alle andere Methoden von anderen Objekten auch nutzen (so wie this.toString) oder geht das nicht?

          Auf jeden Fall nochmals vielen Dank! Jetzt habe ich eine sehr gute Grundlage für andere Artikel oder Tutorials :-) Danke!

          ciao, ww

          --
          Dies ist eine sehr einfache und effektive Sicherheitsstufe, aber nicht perfekt. Denn wenn mehrere User über eine Leitung ins Internet gehen, haben für den Webserver alle User die selbe IP. Und dann wirkt diese Sicherheitsstufe nicht mehr. Aber zumindest könnt ihr demjenigen, der euch die Session-ID geklaut hat, eins in die Fresse hauen.
          http://tut.php-q.net/login.html
          1. Hallo,

            Kann ich zum Beispiel mit this.write() dafür sorgen, dass etwas geschrieben wird? Kann ich mit dem Schlüsselwort this alle andere Methoden von anderen Objekten auch nutzen (so wie this.toString) oder geht das nicht?

            Das mit toString hast du anscheinend noch nicht verstanden - Mit dem Schlüsselwort this kannst du überhaupt nicht »alle anderen Methoden von anderen Objekten nutzen«. Nochmal, das toString aus Cheatahs Beispiel ist nicht das toString von Number-Objekten.

            this zeigt allgemein gesagt auf das Objekt, in dessen Kontext eine Funktion ausgeführt wird.
            Wenn du new Funktion() schreibst und darin this benutzt, dann zeigt this - wie gesagt - auf ein neues, leeres Object, das ist die erzeugte Instanz.
            Wenn du einfach nur Funktion() aufrufst, dann zeigt this auf das window-Objekt. Dasselbe gilt wenn du einfach außerhalb jeder Funktion this verwendest. Wenn du dann this eine Eigenschaft anhängst, erzeugst du eine globale Variablen (globale Variablen sind nichts als Eigenschaften des obersten window-Objektes).

            Mathias

            1. Hallo!

              Ok. Danke schön! Jetzt habe ich es verstanden.

              ciao, ww

              --
              Dies ist eine sehr einfache und effektive Sicherheitsstufe, aber nicht perfekt. Denn wenn mehrere User über eine Leitung ins Internet gehen, haben für den Webserver alle User die selbe IP. Und dann wirkt diese Sicherheitsstufe nicht mehr. Aber zumindest könnt ihr demjenigen, der euch die Session-ID geklaut hat, eins in die Fresse hauen.
              http://tut.php-q.net/login.html
          2. hi,

            Kann ich zum Beispiel mit this.write() dafür sorgen, dass etwas geschrieben wird?

            Nur, wenn du für das Objekt, in deren Kontext du das benutzt, eine Methode write definiert hast.

            Kann ich mit dem Schlüsselwort this alle andere Methoden von anderen Objekten auch nutzen (so wie this.toString) oder geht das nicht?

            Nein, this verweist immer auf das Objekt, in dessen Kontext du es benutzt - dafür ist es ja da.

            Wenn du Methoden anderer Objekte aufrufen möchtest, dann machst du das über Objektreferenz.Methode() - dazu muss dir natürlich eine Referenz auf diese Objektinstanz vorliegen, und die Methode von aussen aus aufrufbar sein.

            gruß,
            wahsaga

            --
            /voodoo.css:
            #GeorgeWBush { position:absolute; bottom:-6ft; }
            1. Hallo!

              Danke für deine Antwort.

              Wenn du Methoden anderer Objekte aufrufen möchtest, dann machst du das über Objektreferenz.Methode() - dazu muss dir natürlich eine Referenz auf diese Objektinstanz vorliegen, und die Methode von aussen aus aufrufbar sein.

              Nur aus interesse: wie sorge ich dafür, dass eine Methode von außen nicht aufrufbar ist?

              ciao, ww

              --
              Dies ist eine sehr einfache und effektive Sicherheitsstufe, aber nicht perfekt. Denn wenn mehrere User über eine Leitung ins Internet gehen, haben für den Webserver alle User die selbe IP. Und dann wirkt diese Sicherheitsstufe nicht mehr. Aber zumindest könnt ihr demjenigen, der euch die Session-ID geklaut hat, eins in die Fresse hauen.
              http://tut.php-q.net/login.html
              1. Hallo,

                Nur aus interesse: wie sorge ich dafür, dass eine Methode von außen nicht aufrufbar ist?

                Wenn ein Funktionsobjekt an einem Objekt (z.B. an der Instanz) hängt, dann ist diese Funktion auch von überall aufrufbar, wo man auf das Objekt zugreifen kann. Das einzige, was man also machen kann, ist, das Funktionsobjekt nicht an die Instanz zu hängen.

                »Private« Methoden wie in anderen OOP-Sprachen gibt es nicht direkt in JavaScript. Man kann denselben Effekt aber um drei Ecken herum nachbauen.

                Private Methoden sind Methoden, die eben nur in der Konstruktorfunktion selbst sowie von priviligierten (das sind im Konstruktor definierte) Methoden aufgerufen werden können.

                Wie sorgt man nun für solche private Methoden? Indem man sie einfach als lokale Variablen im Konstruktor notiert:

                function Konstruktorfunktion () {  
                   var meineKleinePrivateMethode = function () { alert("Möp."); };  
                   meineKleinePrivateMethode(); // Hier gehts.  
                   this.oeffentlicheMethode = function () {  
                      meineKleinePrivateMethode(); // Hier gehts auch. Warum? Weil die verschachtelte Funktionen Zugriff auf die lokalen Variablen der äußeren Funktion haben. Das nennt sich [link:http://aktuell.de.selfhtml.org/artikel/javascript/organisation/index.htm#closures@title=Closures].  
                   };  
                }  
                var instanz = new Konstruktorfunktion;  
                alert(instanz.meineKleinePrivateMethode); // gibbet nich, die Methode hängt nicht an der Instanz.  
                instanz.oeffentlicheMethode(); // Das geht, weil die Methode an das Instanzobjekt geklebt wurde.
                

                Siehe auch Woher kommen die Privilegien von priviligierte Methoden?

                Mathias

                  1. Hallo!

                    Wow. Danke! Jetzt bin ich ja bestens gerüstet für OOP mit Javascript. Danke!

                    ciao, ww

                    --
                    Dies ist eine sehr einfache und effektive Sicherheitsstufe, aber nicht perfekt. Denn wenn mehrere User über eine Leitung ins Internet gehen, haben für den Webserver alle User die selbe IP. Und dann wirkt diese Sicherheitsstufe nicht mehr. Aber zumindest könnt ihr demjenigen, der euch die Session-ID geklaut hat, eins in die Fresse hauen.
                    http://tut.php-q.net/login.html