Hi Uschi!
Ich glaube, Deine Fragen sind ganz gut in http://developer.netscape.com/docs/manuals/js/client/jsguide/obj2.htm#1008342 beantwortet, wenn auch vielleicht nicht wirklich gut erklaert.
Netscape ist der Meinung, zwischen klassenbasierter OOP (Objektorientierte Programmierung) und Protoypen-basierter OOP unterscheiden zu muessen, oder besser gesagt, letzteres erfinden(?) zu muessen.
Klassenbasiert ist das, was Bio und Stefan Dir schon ansatzweise erlaeutert haben und wonach Du ja auch gefragt hast. Es wird dort zwischen der reinen Beschreibung, wie ein Ding "aussieht" und funktioniert (der Klassendefinition) einerseits und der konkreten Existenz eines Objektes (der Instanz) dieses so definierten Typs auf der anderen Seite unterschieden. So kann ich z.B. sagen, eine Strecke (im mathematischen Sinn; also eine Linie von einem Punkt zum anderen mit endlicher Laenge) hat einen Anfangspunkt und einen Endpunkt sowie eine Laenge. Das sind die *Eigenschaften*, aus denen sich eine Strecke definiert. So habe ich die Klasse beschrieben. Instanzen dieser Klasse waeren unter anderem eine Strecke, die von Punkt (1/2/3) bis (1/2/7) verlaeuft und somit eine Laenge von 4 (Laengeneinheiten) hat, eine andere Instanz waere (4/2/8)-(-3/2/8) mit der Laenge 7. (Ja, ich hab die Zahlen so gewaehlt, dass ich Pythagoras nicht anstrengen muss. *g*)
Ausserdem kann ich einer Klasse *Methoden* hinzufuegen, was klasseneigene Funktionen sind, die letzlich die *Eigenschaften* einer Instanz in definierter Weise manipulieren. So koennte eine Methode Move() die Strecke um einen Vektor verschieben. Hierzu muss ich beschreiben, wie genau so ein Verschieben vor sich geht. Bekanntlich muss man einfach den Vektor auf jeden der Punkte der Gerade addieren. Wenn ich genau das in Code presse, habe ich die Klassendefinition um eine Methode erweitert.
JavaScript verfolgt dieses klassenorientierte Modell jedoch nicht; stattdessen wird das prototypen-orientierte verwendet (dazu gleich). Nach meiner Meinung ist jedoch zu bezweifeln, ob dies ueberhaupt noch als "objektorientiert" ernstzunehmen ist. Im Sinne einer sauberen Programmierung sollte man auf die Moeglichkeiten, die aus dem Javascript-Konzept entstehen, besser verzichten (imho natuerlich) und versuchen, sich auf das klassische klassenorientierte zu beschraenken, soweit das von JS ueberhaupt unterstuetzt wird.
Hier erstmal die direkte Uebersetzung des obigen Beispiels nach JS:
// Der sog. Konstruktor eines Objektes
// initialisiert die *Member* (Eigenschaften) einer
// Instanz und bringt sie in einen definierten Zustand
function Strecke(x1, y1, z1, x2, y2, z2) {
// Eigenschaften mit uebergebenen Werten initialisieren
this.x1 = x1; this.y1 = y1; this.z1 = z1;
this.x2 = x2; this.y2 = y2; this.z2 = z2;
this.len = 0;
// Methoden bekannt machen
this.CalcLength = Strecke_CalcLength; // ohne Klammern!
this.Move = MoveYourAss; // Namen koennen natuerlich frei gewaehlt werden
this.GetLength = new Function("return this.GetLength");
// http://developer.netscape.com/docs/manuals/js/client/jsref/function.htm
// Laenge durch Methode CalcLength() initialisieren lassen
this.CalcLength(); // mit Klammern -> Methode aufrufen
}
function Strecke_CalcLength() {
var a, b, c;
a = this.x2 - this.x1;
b = this.y2 - this.y1;
c = this.z2 - this.z1;
this.len = Math.sqrt(a*a + b*b + c*c);
return this.len;
}
function MoveYourAss(dx, dy, dz) {
with (this) {
x1 += dx; x2 += dx;
y1 += dy; y2 += dy;
z1 += dz; z2 += dz;
}
}
Soweit die Klassendefinition. Ich kann jetzt mit
a = new Strecke(1, 2, 3, 1, 2, 7);
b = new Strecke(4, 2, 8, -3, 2, 8);
die oben genannten Instanzen erzeugen. Ich kann jetzt die Laenge abfragen:
lena = a.GetLength();
lenb = b.GetLength();
Dadurch wird die Funktion, die hinter GetLength steht (in diesem Fall ein on the fly erzeugtes Function-Objekt) aufgerufen, wobei die spezielle Variable this auf genau die Instanz zeigt, fuer welches die Methode invoked wird.
Soweit habe ich mich an das Klassenkonzept gehalten. Die Sache mit den Prototypen bedeutet nun, dass die mit dem new-Operator erzeugte Instanz keineswegs ewig das in der Klasse fest definierte Aussehen beibehalten muss, sondern das so erzeugt Objekt lediglich als Prototyp angesehen wird, es aber nachtraeglich im Aussehen geaendert werden kann. Soll heissen, ich kann mit
a.masse = "3 kg";
der Strecke a einfach eine weitere Eigenschaft hinzufuegen (die offensichtlich nicht viel mit einer Strecke zu tun hat). Die Strecke b hat diese Eigenschaft dann aber trotzdem nicht. Somit haben die verschiedenen "Instanzen" (naja, nicht wirklich Instanzen) eigentlich nicht mehr viel miteinander zu tun. Genau so kann ich bei window.history eine x-beliebige Eigenschaft hinzufuegen, aber Sinn macht das sicher kaum.
Und genau das geht in einer "richtigen" OO-Sprache nicht (wobei Java und C++ eigentlich auch noch manches aus der OO-Theorie vermissen lassen).
Wir hatten jetzt also die Begriffe Klasse und Instanz, deren Bedeutung in JS jedoch verblasst. Der Begriff Objekt wird meistens als Synonym fuer Instanz benutzt.
Es gibt ein Objekt namens images, das ist vorgefertigt. Wenn ich nun ein Bildchen in meine Datei einbinde,
»»
<img src="bildchen.gif" height="10" width="10" name="blubber">
»»
ist das dann ein Objekt oder die Instanz eines Objekts images, und worin liegt der Unterschied, und was wäre dann eine Klasse?
Wenn der Browser die Datei laedt, wird fuer jedes <img> eine Instanz der Klasse Image erzeugt und in das images-Array eingehaengt. Das sind Wrapper-Objekte, wodurch der Zugriff auf das Dokument ermoeglicht werden soll.
Da Objekte und Arrays in JS aber dasselbe sind, ist document.images selbst nicht nur ein Array, das lauter Image-Instanzen enthaelt, sondern es ist (leider) auch richtig, wenn man es als auch als Objekt bezeichnet, welches die einzelnen Bilder als Eigenschaften hat. Dann ist es aber ein sehr armseliges Objekt, denn es ist tatsaechlich nichts anderes als eine blosse Auflistung und bietet keinerlei Mehrwert. (Die Strecke hatte z.B. die Methode Move(), die einem die Arbeit abnimmt, selbst die Addition des Vektors durchzufuehren, und somit etwas mehr kann, als ein blosses Array, welches die sechs Werte fuer die zwei Eckpunkte speichert.)
Ich habe aus Selfhtml gelernt, daß die images eines Dokuments vom Browser als Array behandelt werden.
Also Array == normale Variablen oder Objekte, je nachdem, was drin ist?
Arrays und Objekte sind in JS dasselbe. Es handelt sich einfach um zwei verschiedene Schreibweisen fuer den Zugriff auf ein und dieselbe Datenstruktur.
document.images.bildname
document.images["bildname"]
document["images"].bildname
document["images"]["bildname"]
Alles dasselbe. Zu beachten ist vielleicht noch, dass Arrays in JS sogenannte assoziative Arrays sind, d.h. als Index koennen nicht nur Zahlen verwendet werden, sondern auch Strings.
Noch was: Ein Objekt ist eigentlich eine Referenz auf ein Objekt. Dass heisst, mit
a = new Strecke(1, 2, 3, 1, 2, 7);
bekomme ich nach a kein Objekt an sich, sondern einen Zeiger, der auf eine Struktur irgendwo in den Speichertiefen des Browsers verweist. Das entscheidende dabei ist, dass ich mit
a = c;
keineswegs ein ganzes Objekt kopiere und hinterher zwei habe, sondern nur die Referenz kopiert wird und dann beide Variablen auf *ein und dasselbe* Objekt zeigen. Rufe ich also
a.Move(2, 5, 3);
auf, sehe ich die Aenderung auch mit alert(c.x1). Siehe auch <../../sfarchiv/2000_1/t10312.htm#a51977>, evtl auch <../../sfarchiv/2000_1/t10566.htm#a53329>.
(Eine Methode ist nur eine Referenz auf ein Function-Objekt, weshalb a.Move auch saemtliche in http://developer.netscape.com/docs/manuals/js/client/jsref/function.htm gelisteten Eigenschaften hat, incl. toSource. Just try alert(a.Move.toSource()).)
Ganz einfach, das alles, ne? Aber frag ruhig weiter, wenn noetig. ;-)
Naja, eigentlich wollte ich Dich ja nur auf den erstgenannten Link verweisen, weil da steht ja alles drin und noch viel mehr, aber dann bin ich wohl ins Schwafel gekommen. *g*
So long, Roland