Basisklasse und Vererbung
jack
- javascript
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;
;
}
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;
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
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
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
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
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
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