jack: Basisklasse und Vererbung

Hallo,

ich möchte in Javascript, die folgende Klasse (nur eine Auszug )als Basisklasse benutzen und jetzt davon ableiten. Wie mache ich das? Kennt jemand ein Tutorial dazu?

Mir geht es vor allem um das Überschreiben von Methoden und dem Hinzufügen von Attributen (mache ich das irgendwie mit prototype?)

function EingabeElement(x,y) {
 this.x = x;
 this.y = y;
 this.elementId = 0;

this.setX = function(sX) {
            this.x = sX;
        ;

}

  1. function EingabeElement(x,y) {
    this.x = x;
    this.y = y;
    this.elementId = 0;

    this.setX = function(sX) {
                this.x = sX;
            ;

    }

    Ich habe so versucht, hat aber nicht geklappt und da SELFHTML da leider keine Infos zu bietet (call habe ich zB nicht gefunden), wäre es schön, wenn mir hier einer helfen kann.

    function Knopf(x,y,beschriftung) {
     //Super-Konstruktor aufrufen
     EingabeElement.call(this,x,y);

    //Attribute
     this.value = beschriftung;

    return this;
    }
    //Ableiten
    Knopf.prototype = new EingabeElement();
    Knopf.prototype.constructor = Knopf;

    1. Hallo,

      function Knopf(x,y,beschriftung) {
      //Super-Konstruktor aufrufen
      EingabeElement.call(this,x,y);

      //Attribute
      this.value = beschriftung;

      return this;
      }
      //Ableiten
      Knopf.prototype = new EingabeElement();
      Knopf.prototype.constructor = Knopf;

      http://de.wikipedia.org/wiki/Javascript#Vererbung_.28prototype-Eigenschaft.29

      Wozu braucht man call() denn überhaupt? In this.constructor steht eine Referenz zu EingabeElement. Denn Sinn von Knopf.prototype.constructor = Knopf verstehe ich nicht.

        
      function EingabeElement(x,y) {  
       this.x = x;  
       this.y = y;  
       this.elementId = 0;  
       this.setX = function (sX) {  
        this.x = sX;  
       };  
      }  
      function Knopf (x, y, beschriftung) {  
       alert(this.constructor === EingabeElement);  
       this.constructor(x, y);  
       this.value = beschriftung;  
      }  
        
      Knopf.prototype = new EingabeElement();  
        
      var beispielknopf = new Knopf(1, 2, "Titel");  
      alert(beispielknopf.elementId);  
      beispielknopf.setX(3);  
      alert(beispielknopf.x + "\n" + beispielknopf.value);  
      
      

      Mathias

      1. Wozu braucht man call() denn überhaupt? In this.constructor steht eine Referenz zu EingabeElement. Denn Sinn von Knopf.prototype.constructor = Knopf verstehe ich nicht.

        Das habe ich auch nicht verstanden. Ich hatte es einfach nur abgetippt.

        function EingabeElement(x,y) {
        this.x = x;
        this.y = y;
        this.elementId = 0;
        this.setX = function (sX) {
          this.x = sX;
        };
        }
        function Knopf (x, y, beschriftung) {
        alert(this.constructor === EingabeElement);

        Was machen denn die 3 Gleichheitszeichen?

        this.constructor(x, y);

        constructor ist doch irgendeine Funktion. Ist die vorgegeben? Warum muss ich jetzt explizit einen Konstruktor aufrufen? Das muss ich doch sonst nicht machen?

        this.value = beschriftung;
        }

        Knopf.prototype = new EingabeElement();

        var beispielknopf = new Knopf(1, 2, "Titel");
        alert(beispielknopf.elementId);
        beispielknopf.setX(3);
        alert(beispielknopf.x + "\n" + beispielknopf.value);

        
        >   
          
        Ansonsten schönen Dank für deine Hilfe. Es hilft mir sehr weiter.  
          
        Jack  
        
        
        1. Hallo,

          function Knopf (x, y, beschriftung) {
          alert(this.constructor === EingabeElement);

          Was machen denn die 3 Gleichheitszeichen?

          Das ist der Identitätsoperator. this.constructor === EingabeElement gibt zurück, ob die beiden Objekte identisch sind. Sie sind es, also kann man this.constructor() aufrufen. Daher zur Verdeutlichung dieser alert.

          this.constructor(x, y);

          constructor ist doch irgendeine Funktion. Ist die vorgegeben?

          constructor ist die Konstruktorfunktion des Prototyps, also der Basisklasse (siehe).

          Warum muss ich jetzt explizit einen Konstruktor aufrufen? Das muss ich doch sonst nicht machen?

          In der Konstruktorfunktion (im Folgenden einfach: Konstruktor) von EingabeElement setzt du die Eigenschaften, darunter eine öffentliche, priviligierte Funktion. Du benutzt dabei Parameter, die dem Konstruktor übergeben wurden. Das ist das Problem.

          function EingabeElement (x,y) {  
           alert("Konstruktor EingabeElement aufgerufen");  
           this.x = x;  
           this.y = y;  
           this.elementId = 0;  
           this.setX = function (sX) {  
            this.x = sX;  
           };  
          }  
          function Knopf (x, y, beschriftung) {  
           // this.constructor(x, y);  
           this.value = beschriftung;  
          }  
            
          Knopf.prototype = new EingabeElement();  
          alert(Knopf.prototype.x);  
          alert(Knopf.prototype.setX);  
            
          var beispielknopf = new Knopf(1, 2, "Titel");  
          alert(beispielknopf.x);  
          alert(beispielknopf.setX);
          

          Als Prototyp für Knopf wird eine Instanz von EingabeElement verwendet. Dazu wird der EingabeElement-Konstruktor aufgerufen - aber ohne Parameter. Die Methode setX wird korrekt vererbt, aber die Parameter x und y, die du dem Knopf-Konstruktor übergibst, werden nicht in den Objekteigenschaften x und y gespeichert.

          Man hat einige Möglichkeiten, um das Problem zu umgehen. Entweder man schreibt
           this.x = x;
           this.y = y;
           this.elementId = 0;
          noch einmal in den Knopf-Konstruktor. Oder man ruft eben wie gezeigt den EingabeElement-Konstruktor im Knopf-Konstruktor noch einmal auf, diesmal mit Parametern.

          Wenn man alle Methoden/Eigenschaften nur im Konstruktor notiert, dann braucht man Knopf.prototype = new EingabeElement; eigentlich nicht. Denn alle Eigenschaften/Methoden werden ja sowieso beim Aufruf des EingabeElement-Konstruktors im Knopf-Konstruktor kopiert. Allerdings funktioniert dann der Zugriff auf this.construtor nicht.

          In dem Fall könntest du EingabeElement.call(this, x, y); verwenden. Oder man hängt EingabeElement als Methode an this. Dann wird es ebenfalls im Kontext der aktuellen Instanz ausgeführt, das heißt »this« in der EingabeElement-Methode verweist auf die aktuelle Instanz.

          function EingabeElement (x,y) {  
           alert("Konstruktor EingabeElement");  
           this.x = x;  
           this.y = y;  
           this.elementId = 0;  
           this.setX = function (sX) {  
            this.x = sX;  
           };  
          }  
          function Knopf (x, y, beschriftung) {  
           this.constructor = EingabeElement;  
           this.constructor(x, y);  
           this.value = beschriftung;  
          }  
            
          var beispielknopf = new Knopf(1, 2, "Titel");  
          alert(beispielknopf.x);  
          alert(beispielknopf.setX);
          

          Das ist dann aber eine prototypische Vererbung mehr. Man kann zwar Eigenschaften/Methoden über EingabeElement.prototype.XYZ definieren, sie werden aber nicht an Instanzen von Knopf vererbt.

          Siehe auch http://forum.de.selfhtml.org/archiv/2005/2/t100600/ und http://phrogz.net/JS/Classes/OOPinJS2.html.

          Mathias

        2. gruss Jack,

          den ausfuehrungen und links von molily in
            https://forum.selfhtml.org/?t=124977&m=805605
            moechte ich noch ein paar grundlegende ueberlegungen
            zu dem von Dir aufgeworfenen vererbungsfall anhand
            eines kommentierten beispiels und 2 moegliche loesungen,
            Dein beispiel betreffend, hinzufuegen.

          ausserdem sei Dir die lektuere von Douglas Crockfords
            JavaScript-artikeln ans herz gelegt:

          http://javascript.crockford.com/ - besonders die

          zu Kapselung und Vererbung.

          los gehts:

          var BaseConstructor = function (/*any arguments*/) {  
            
            this.construcor = arguments.callee; /* ist identisch zu:  
            this.construcor = BaseConstructor; */  
            
          /*  
            folgende eigenschaften und methoden lassen sich nur  
            innerhalb des funktionsrumpfes eines konstruktors  
            vereinbaren:  
          */  
            
          //private eigenschaften:  
            var privateProperty1 = arguments[0];  
            var privateProperty2 = arguments[1];  
            
          //private methoden:  
            var privateMethod1 = function (/*up to you*/) {/*your stuff*/};  
            var privateMethod2 = function (/*up to you*/) {/*your stuff*/};  
            
          //oeffentliche privilegierte methoden:  
            
            /*setter: kontrollierter zugriff auf  
              private eigenschaften und methoden;  
            */  
            this.publicPrivilegedSetterMethod = function (/*any arguments*/) {  
              /*  
                assign this functions arguments to your private properties  
                or pass them over to your private methods;  
              */  
            };  
            
            /*getter: kontrollierte rueckgabe  
              privater eigenschaften und methoden;  
            */  
            this.publicPrivilegedGetterMethod = function () {  
              /*  
                return private stuff;  
              */  
            };  
            
          /*  
            alle oeffentlichen nicht privilegierten methoden eines objekts  
            sollten sowiso als eigenschaften des prototypen-objekts seines  
            konstruktors vereinbart werden.  
            
            selbiges gilt fuer oeffentliche eigenschaften, die fuer alle  
            objekte einer objektfamilie gleich lauten und deren initialer  
            wert fuer alle objekte identisch ist.  
            
            im bsp. wird fuer den basis-konstruktor "Car" die anzahl der  
            raeder ohne umschweife wie folgt festgelegt:  
            
            var Car = function () {};  
            Car.prototype.amountOfWheels = 4;  
            
            konstruktoren spezieller fahrzeugmarken muessen sich nicht  
            mehr um diese eigenschaft kuemmern, wenn folgenden zeilen  
            beachtung geschenkt wurde:  
            
            var CarBrand = function () {};  
            CarBrand.prototype = new Car();  
            
            weiterhin kann man die deklarierung/initialisierung aller  
            oeffentlichen eigenschaften, die fuer die konstruktoren einer  
            objektfamilie gleich lauten in eine entsprechende oeffentliche  
            nicht privilegierte methode - z.b.: "compile" , "initialize" -  
            auslagern.  
          */  
            this.initialize.apply(this,arguments);  
          };  
            
          //methoden des objektprototypen (oeffentlich und nicht privilegiert):  
            
            BaseConstructor.prototype.initialize = function (/*any arguments*/) {  
            
            //oeffentliche eigenschaften:  
              this.publicProperty1 = arguments[2];  
              this.publicProperty2 = arguments[3];  
            };  
            
            
          /*  
            konstruktor, dessen objekte auf objekten  
            des typs "baseconstructor" aufbauen sollen:  
          */  
          var BaseEnhancer = function (/*any arguments*/) {  
            
            this.construcor = arguments.callee; /* identical to:  
            this.construcor = BaseEnhancer; */  
            
            var privateProperty1 = arguments[0];  
            var privateProperty2 = arguments[1];  
            
            var privateMethod1 = function (/*up to you*/) {/*your stuff*/};  
            var privateMethod2 = function (/*up to you*/) {/*your stuff*/};  
            
            this.publicPrivilegedSetterMethod = function (/*any arguments*/) {  
            //to exemplify  
              privateProperty1 = arguments[0];  
            };  
            this.publicPrivilegedGetterMethod = function () {  
            //to exemplify  
              return privateProperty1;  
            };  
            /*  
              an dieser stelle wird die methode "initialize" des  
              objektprototypen "BaseConstructor" im kontext von  
              "BaseEnhancer" ausgefuehrt.  
            */  
            this.initialize.apply(this,arguments);  
            /*  
              im gegebenen bsp. besaesse ein objekt vom typ  
              "baseenhancer" jetzt auch die oeffentlichen  
              eigenschaften "publicProperty1" sowie "publicProperty2".  
            */  
          };  
          BaseEnhancer.prototype = new BaseConstructor();  
            
            
          //Dein ausgangscode - von mir kommentiert:  
            
            function EingabeElement(x,y) {  
            
            //oeffentliche eigenschaften:  
              this.x = x;  
              this.y = y;  
              this.elementId = 0;  
            
            //eine setter methode ist doch nur dann sinnvoll,  
            //wenn die entsprechend zu setzenden eigenschaften  
            //privat statt oeffentlich sind.  
              this.setX = function(sX) {  
                this.x = sX;  
              };  
            }  
            function Knopf(x,y,beschriftung) {  
            
             //Super-Konstruktor aufrufen  
             EingabeElement.call(this,x,y);  
            
             //Attribute  
             this.value = beschriftung;  
            
             return this; // kann man (muss man nicht) weglassen;  
            }  
            //Ableiten  
            Knopf.prototype = new EingabeElement();  
            
            
          //umsetzung 1) alles oeffentlich:  
            
            var EingabeElement = function (x, y) {  
            
            //oeffentliche eigenschaften:  
              this.x = x;  
              this.y = y;  
            
              this.elementId = 0;  
            };  
            var Knopf = function (x, y, beschriftung) {  
            
            //"super-konstruktor" aufrufen:  
              EingabeElement.call(this,x,y); /* oder:  
              EingabeElement.apply(this,arguments); oder:  
              this.constructor.call(this,x,y); oder:  
              this.constructor.apply(this,arguments); */  
            
            //weitere oeffentliche eigenschaft:  
              this.value = beschriftung;  
            };  
            //ableiten:  
            Knopf.prototype = new EingabeElement();  
            
          /*  
            bei dieser umsetzung gilt fuer jedes objekt vom typ "knopf":  
            
            ((knopfObject.constructor === EingabeElement) === true);  
            
            da dessen "constructor"-referenz vom objektprototypen -  
            einem objekt vom typ "eingabeelement" - ueberschrieben wird.  
            
            
            um direkte referenzen zu erhalten muss man anders vorgehen:  
          */  
            
          //umsetzung 2) alles oeffentlich:  
            
            var EingabeElement = function (x, y) {  
            
              this.constructor = arguments.callee;  
              this.compile.apply(this,arguments);  
            };  
            EingabeElement.prototype.compile = function () {  
            
            //oeffentliche eigenschaften:  
              this.x = arguments[0];  
              this.y = arguments[1];  
            
              this.elementId = 0;  
            };  
            var Knopf = function (x, y, beschriftung) {  
            
              this.constructor = arguments.callee;  
            
            //super-konstruktion im kontext von "Knopf":  
              this.compile.apply(this,arguments);  
            
            //weitere oeffentliche eigenschaft:  
              this.value = beschriftung; /* oder  
              this.value = arguments[2]; */  
            };  
            //ableiten:  
            Knopf.prototype = new EingabeElement();  
            
          /*  
            fuer umsetzung 2) gilt fuer jedes objekt vom typ "knopf":  
            
            ((knopfObject.constructor === Knopf) === true);  
          */  
            
          /*umsetzung 3) private eigenschaften und setter/getter:  
            
            da private eigenschaften/methoden sowie deren getter- bzw.  
            setter-methoden unmittelbar im funktionsrumpf eines  
            konstruktors notiert werden muessen, ist es um vererbungs-  
            muster schlecht bestellt.  
            
            im gegebenen bsp. findet vererbung ueberhaupt nicht statt,  
            da keinerlei eigenschaften und methoden existieren, die  
            den weg in die prototypenkette nehmen koennten.  
          */  
            var EingabeElement = function (newX, newY) {  
            
              var x = newX;  
              var y = newY;  
              var elementId = 0;  
            
              this.setX = function (newX) {  
                x = newX;  
              };  
              this.setY = function (newY) {  
                y = newY;  
              };  
              this.setElementId = function (newId) {  
                elementId = newId;  
              };  
              this.getX = function () {return x;};  
              this.getY = function () {return y;};  
              this.getElementId = function () {return elementId;};  
            };  
            var Knopf = function (newX, newY, beschriftung) {  
            
              var x = newX;  
              var y = newY;  
              var elementId = 0;  
            
            //eine oeffentliche eigenschaft:  
              this.value = beschriftung;  
            
              this.setX = function (newX) {  
                x = newX;  
              };  
              this.setY = function (newY) {  
                y = newY;  
              };  
              this.setElementId = function (newId) {  
                elementId = newId;  
              };  
              this.getX = function () {return x;};  
              this.getY = function () {return y;};  
              this.getElementId = function () {return elementId;};  
            };
          

          so long - peterS. - pseliger@gmx.net

          --
          "Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
          Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive." - Douglas Crockford
          ie:( fl:) br:> va:( ls:& fo:) rl:| n3;} n4:} ss:} de:µ js:} mo:? zu:]
    2. Moin!

      Ich habe so versucht, hat aber nicht geklappt und da SELFHTML da leider keine Infos zu bietet (call habe ich zB nicht gefunden), wäre es schön, wenn mir hier einer helfen kann.

      Wir haben ja auch noch Featureartikel und so'n Zeugs. Den hier zum Beispiel:
      http://aktuell.de.selfhtml.org/artikel/javascript/oomodell/index.htm

      - Sven Rautenberg

      --
      My sssignature, my preciousssss!