Hoch Inhalt dieses Kapitels:

Linkwerk
screeneXa

Erhältlich u.a. bei  Amazon.de

4

Eigene Objekte

Von Christine Kühnel

4.1 Grundlagen

Sie haben im vorangegangenen Kapitel gesehen, dass sich Ihre eigenen Variablen als Eigenschaften von window im Objektbaum wiederfinden. Damit ist die Frage nahe liegend, ob man auch eigene Objekte definieren kann. Natürlich kann man das. Im Interesse übersichtlicher, sauber strukturierter Programmierung ist es bei etwas komplexeren Aufgaben sogar sinnvoll, mit eigenen Objekten zu arbeiten.

4.1.1 Eigene Objekte definieren

new-Operator

Sie erinneren sich an diesesBuch und meinRoman, die Objekte aus Kapitel 3? Die wollen wir jetzt gemeinsam definieren. Zwei Dinge sind dafür erforderlich. Zunächst brauchen wir einen eigenen Objekttyp, in unserem Fall ist es das Buch. Die Aufgabe, diesen Typ zu definieren, übernimmt eine Funktion. In der Regel werden darin auch gleich die notwendigen Eigenschaften und Methoden angelegt. Außerdem benötigen wir einen Operator, der uns Instanzen, also unsere einzelnen Objekte vom Typ Buch aufbaut; dafür gibt es new, einen Operator, der ein Objekt anlegt mit Hilfe eines Konstruktors, so nennt man die Funktion, die den Objekttyp definiert. new sind Sie bereits in diesem Buch begegnet, denken Sie an

var meinArray = new Array();

Konstruktor-Funktion

Sie haben das Objekt meinArray angelegt, indem Sie mit Hilfe von new eine Instanz des Typs Array definiert haben. Die Funktion Array() ist z.B. so ein Konstruktor, nur mussten Sie die nicht selbst schreiben, weil sie der Browser bereits vordefiniert enthält. Aber wir wollen jetzt eigene, dem Browser noch unbekannte Objekte definieren und müssen uns deswegen um einen geeigneten Konstruktor selbst kümmern. So könnte zum Beispiel die Konstruktor-Funktion für den Objekttyp Buch aussehen:

Beispiel

function Buch(pTitel, pVerlag, pSeiten)
{
   this.Titel  = pTitel;
   this.Verlag = pVerlag;
   this.Seiten = pSeiten;
}

this-Keyword

Sie erkennen die Eigenschaften wieder, die wir bereits im vorangegangenen Kapitel betrachtet haben. Die Erklärung, was es mit this auf sich hat, bin ich Ihnen noch schuldig. this ist ein Keyword 1, das immer auf das Objekt selbst weist, Sie können es auch innerhalb von Methoden jederzeit verwenden. Zusammen mit der Konstruktor-Funktion haben wir die Voraussetzungen, unsere einzelnen Objekte anzulegen, zum Beispiel:

diesesBuch = new Buch("JavaScript Workshop",
                      "Addison-Wesley", 300);

Als Parameter haben wir der Konstruktor-Funktion die konkreten Werte der Eigenschaften Titel, Verlag und Seiten für diesesBuch übergeben. Lassen wir uns jetzt die Werte auflisten, etwa mit

Beispiel

<script language="JavaScript" type="text/javascript">
<!--
document.writeln('Das Buch "'+diesesBuch.Titel+'" ');
document.writeln(' von "'+diesesBuch.Verlag+'" hat ca. ');
document.writeln(diesesBuch.Seiten+' Seiten.');
// -->
</script>

Wir erhalten eine solche Ausgabe:

beispiel0401.html -

Objekt als Eigenschaft

Ist Ihnen aufgefallen, dass das noch gar nicht alle Eigenschaften sind, die uns an so einem Buch interessieren sollten? Richtig, der Einband fehlt. Der war insofern eine Besonderheit, dass er selbst wieder ein Objekt sein sollte. Wie geben wir dem Objekt diesesBuch eine solche Eigenschaft Einband? Sie ahnen es, wir benötigen einen Objekttyp und damit eine Konstruktor-Funktion

function Einband(pFarbe, pArt)
{
   this.Farbe  = pFarbe;
   this.Art    = pArt;
}

Bevor wir uns darum kümmern, die Konstruktor-Funktion für Buch entsprechend zu ergänzen, denken wir gleich noch daran, dass wir auch eine Eigenschaft offen haben wollten, die uns sagt, ob das Buch geöffnet ist, wenn ja, auf welcher Seite es aufgeschlagen ist. Dafür bietet es sich geradezu an, einen Integer-Wert zu verwenden, man kann darin gleich die Seite unterbringen, auf der das Buch aufgeschlagen ist. 0 soll für "zugeschlagen" stehen.

Methoden sind Referenzen auf Funktionen

Außerdem benötigen wir noch die Methoden für das Auf- und für das Zuschlagen. Methoden sind Referenzen auf Funktionen. Also gehen wir zunächst daran, die Funktionen zu schreiben.

Was muss beim Zuschlagen passieren? Das ist nicht viel. Der Wert von offen muss lediglich auf 0 gesetzt werden:

function zuschlagen()
{
   this.offen = 0;
}

Beim Aufschlagen müssen wir ein ganz klein wenig mehr tun, wir wollen ja eine bestimmte Seite erreichen. Die gewünschte Seite werden wir später beim Aufruf als Parameter übergeben:

Beispiel

function aufschlagen(pSeite)
{
   // erst mal nachsehen, ob es die Seite gibt
   if (0 < pSeite && this.Seiten <= pSeite)
      this.offen = pSeite;
   else
      this.offen = 0;
}

Sie haben recht, für das Zuschlagen braucht man eigentlich gar keine eigene Funktion, ebenso könnte man aufschlagen() mit dem Parameterwert 0 für die Seite aufrufen und würde dasselbe Ergebnis erzielen. Aber lassen wir es der besseren Anschauung wegen bei zwei Funktionen.

Jetzt haben wir endlich alle Vorbereitungen erledigt, können die vollständige Konstruktor-Funktion für den Objekttyp Buch schreiben und gleich im Anschluss das Objekt diesesBuch definieren:

Beispiel

function Buch(pTitel, pVerlag, pSeiten, pFarbe, pArt)
{
   this.Titel       = pTitel;
   this.Verlag      = pVerlag;
   this.Seiten      = pSeiten;
   this.Einband     = new Einband(pFarbe, pArt);
   this.offen       = 0;
   this.zuschlagen  = zuschlagen;
   this.aufschlagen = aufschlagen;
}
diesesBuch = new Buch("JavaScript Workshop",
                      "Addison Wesley", 300,
                      "gelb", "Taschenbuch");

Genau wie diesesBuch können Sie beliebig viele andere Objekte definieren, die vom Objekt-Typ Buch sind. Nehmen wir noch ein anderes JavaScript-Buch:

nocheinBuch = new Buch("JavaScript 1.2",
                       "Addison-Wesley", 500,
                       "weiß", "gebunden");

Schreiben Sie ruhig einmal die Anweisung auf, mit der Sie ein Objekt meinRoman anlegen für den Roman, den Sie gerade lesen.

4.1.2 Eigenschaften und Methoden hinzufügen

Auch nachträglich können einem Objekt Eigenschaften und Methoden hinzugefügt werden. Das macht durchaus Sinn, wenn man vielleicht erst im Laufe der Abarbeitung entscheiden will, ob überhaupt neue Eigenschaften gebraucht werden. Denkbar ist es auch, dass abhängig von anfangs nicht bekannten Umständen verschiedene Eigenschaften nötig sind.

An dieser Stelle müssen Sie aufpassen. Es gilt, zwei grundlegend verschiedene Arten des Hinzufügens zu unterscheiden:

Hinweis

Nehmen wir an, der Autor soll hinzugefügt werden. Dieses Buch hier hat mehrere Autoren, aber das Buch "Javascript 1.2" nur einen, und den setzen wir jetzt ein:

nocheinBuch.Autor ="S. Mintert";

Hat jetzt wirklich nur nocheinBuch die Eigenschaft Autor? Was ist mit diesesBuch?

for... in

Um zu überprüfen, was genau passiert ist, schreiben wir uns zunächst eine kleine Hilfsfunktion, die Details zu einzelnen Objekten liefert. Vorausschicken muss ich dazu etwas zu einer Anweisung, die bisher nicht vorgekommen ist: for ... in durchläuft alle Eigenschaften und Methoden eines Objektes, ist deswegen für unser Anliegen geradezu maßgeschneidert:

function zeigeDetails(Objekt, ObjektName)
{
   var Info    = '<pre>' + ObjektName + ':\n';
   var Details = '';
   for (var i in Objekt)
      Details = Details + i + ' = ' + Objekt[i] + '\n';
   Info = Info + Details + '</pre><hr>';
   return Info;
}
nocheinBuch.Autor ="S. Mintert";
document.writeln(zeigeDetails(diesesBuch, 'diesesBuch'));
document.writeln(zeigeDetails(nocheinBuch, 'nocheinBuch'));

Ein komplexes Beispiel: - beispiel0402.html -

Tatsächlich kommt die Eigenschaft Autor nur bei nocheinBuch vor, diesesBuch hat sie nicht.

Das Hinzufügen von neuen Eigenschaften für alle Objekte desselben Typs ist ab JavaScript 1.1 möglich.

prototype

Buch.prototype.Autor="kenne ich nicht";

fügt allen Objekten, die mit new Buch() definiert wurden, eine Eigenschaft Autor hinzu und initialisiert den Wert mit "kenne ich nicht". Wiederholen wir an dieser Stelle die document.writeln()-Anweisungen von eben, finden wir jetzt bei beiden Objekten die Eigenschaft Autor. Wie sieht es bei meinRoman aus? Haben Sie es ausprobiert? Auch dieses Objekt sollte eine neue Eigenschaft bekommen haben.

Hinweis

Sie können übrigens nicht nur Objekte mit prototype erweitern, deren Konstruktor-Funktion Sie selbst geschrieben haben. Was halten Sie davon, Ihren Arrays eine Beschreibung hinzuzufügen?

Beispiel

var meineListe = new Array();
var deineListe = new Array();
Array.prototype.Beschreibung = 'keine Angabe';
meineListe.Beschreibung = "das gehört mir";
deineListe.Beschreibung = "das gehört dir";

beispiel0403.html -

Der Vollständigkeit halber soll hier noch ganz kurz eine andere Möglichkeit erwähnt werden, Objekte zu definieren, ohne eine Konstruktor-Funktion zu verwenden. In der Praxis werden Sie die vermutlich nicht so sehr oft benutzen, obwohl sie für einfache Objekte recht praktisch ist, denn sie funktioniert leider erst ab JavaScript 1.2. Wenn Sie ganz sicher sind, dass NN3 und Vorgänger mit Ihrem Script ohnehin nicht in Berührung kommen, können Sie diesesBuch auch so definieren:

Beispiel

diesesBuch = {
           Titel: "JavaScript Workshop",
           Verlag: "Addison Wesley",
           Einband: {Farbe: 'gelb' , Art: 'Taschenbuch' },
           Seite: 300,
           offen: 0,
           zuschlagen: zuschlagen,
           aufschlagen: aufschlagen }

4.1.3 Objekte löschen

Zum Löschen gibt es gar nicht viel zu sagen. In JavaScript 1.0 ging es noch gar nicht. Seit JavaScript 1.1 kann man Objekten den Wert null zuweisen. Mit JavaScript 1.2 kommt ein delete-Operator, mit dem sowohl ganze Objekte als auch nur einzelne Eigenschaften gelöscht werden können, MSIE kennt ihn seit Version 4 ebenfalls. Um zum Beispiel die Eigenschaft Autor aus dem Objekt diesesBuch wieder zu löschen, schreiben Sie, um kompatibel zu NN3 zu bleiben:

Beispiel

diesesBuch.Autor = null;

Müssen Sie auf Kompatibilität keine Rücksicht nehmen, dann löschen sie wirklich mit

delete diesesBuch.Autor;

Hinweis

Um sich zu verdeutlichen, dass es tatsächlich einen Unterschied gibt, verwenden sie am besten wieder die Funktion zeigeDetails(). Sie sehen, bei der ersten Variante existiert Autor noch, hat lediglich den Wert null; bei der zweiten ist Autor verschwunden.

Dieses Löschen hat natürlich auch Grenzen. Die Einzelheiten, was Sie wann löschen dürfen, führen hier zu weit. Bei Ihren eigenen Objekten gibt es ohnehin kaum Einschränkungen. Außerdem dürfen Sie es ruhig ausprobieren, delete hat nämlich einen Rückgabwert, Sie erhalten false, wenn das Löschen nicht geklappt hat, sonst natürlich true. Hiermit bekommen Sie unter Garantie false :

4.2 Übungen

Das Beispiel Buch war sicher recht anschaulich, so hoffe ich wenigstens. Nun kommt es auf Webseiten aber eher selten vor, dass Bücher auf- und zugeschlagen werden. Deswegen schauen wir uns nach einem zweiten Beispiel um, diesmal mit etwas mehr Web-Nähe.

Wie wäre es mit einer pflegleichten Linkliste? Sind Sie wie ich ein visueller Typ? Erkennen Sie Bilder leichter wieder als Texte? Dann schauen Sie sich Abbildung 4.1 bitte einmal an. So oder ähnlich könnte eine Liste oft benötigter Links mit kleinen Screenshots zum schnelleren Wiederfinden aussehen. In den nachfolgenden Übungen werden Sie sich mit ein ganz klein wenig Unterstützung von mir so eine Liste Schritt für Schritt aufbauen.

Abbildung 4.1

Abbildung 4.1: Screenshot "eine Linkliste"

Aber beginnen wir zum Aufwärmen mit ein paar einfachen Fragen.

Uebung

leicht

1. Übung

Warum reagiert der Browser hier mit einer Fehlermeldung?

function Heft(Seiten)
{
   this.Seiten = Seiten;
}
meinHeft = Heft(15);
alert (meinHeft.Seiten);

Uebung

leicht

2. Übung

Warum meldet der Browser hier "undefined"?

function Heft(Umschlag)
{
   Heft.Umschlag = Umschlag;
}
meinHeft = new Heft('blau');
alert (meinHeft.Umschlag);

3. Übung

Uebung

mittel

Wie würden Sie Objekte für all Ihre Bücher anlegen und sich die Bücher anschließend auflisten lassen? Verzichten Sie auf die Eigenschaft offen und das Auf- und Zuschlagen, die sind für so eine Liste nicht interessant.

4. Übung

Uebung

mittel

Jetzt kommen wir endlich zu unserer Linkliste. Bauen Sie ähnlich wie gerade eben für die Bücher eine Liste von interessanten Links auf. Folgende Eigenschaften sollen die einzelnen Objekte haben:

Ist für einen Link keine Grafikdatei mit Screenshot vorhanden, soll eine Ersatzgrafik verwendet werden. Die Grafiken haben alle die gleichen Abmessungen.

Definieren Sie zusätzlich eine Methode, die eine Auflistung der eingetragenen Links mit folgenden Angaben ausgibt: Screenshot als Link, Titel als Link, Autor, Thema und Anmerkung.

5. Übung

Uebung

schwer

Die Linkliste aus der letzten Übung ist schon ganz schön. Noch schöner wäre es, man bekäme die Links thematisch geordnet angezeigt. Genau das soll jetzt die Aufgabe sein. Listen Sie die Links so auf, dass alle mit gleichem Thema unter einer Zwischenüberschrift nacheinander erscheinen. Dabei soll die Reihenfolge der Themen gleichgültig sein.

6. Zusatz-Übungen (ohne Lösungen)

In den Übungen 4 und 5 konnte vieles nur ansatzweise realisiert werden. Eine Menge könnte man ergänzen oder noch besser machen. Der Rahmen des Buches lässt es nicht zu, auf das alles einzugehen. Aber vielleicht haben Sie Lust, selbstständig weiterzumachen; die notwendigen Grundlagen dafür haben Sie inzwischen. Ich nenne Ihnen hier einfach ein paar Stichworte, die mir dazu einfallen als Anregung:

Sie sehen, Ihrer Phantasie sind kaum Grenzen gesetzt. Aber Sie sehen auch, falls Sie das nicht längst wissen, mit der Kenntnis von Syntax und Möglichkeiten einer Sprache allein ist es nicht getan. Einen mindestens ebenso breiten Raum wie das Schreiben des Codes nimmt gründliches Nachdenken über Problem, Ziel und den einzuschlagenden Weg ein. Unterschätzen und vor allem, vernachlässigen Sie das bitte nicht.

4.3 Tipps

Tipps zu 2

Probieren Sie aus, was wirklich passiert ist:

alert (Heft.Umschlag);

Tipps zu 3

Das Problem ist hier sicher die Anzahl der Bücher. Es ist wenig sinnvoll, sich für jedes Buch einen eigenen Objektnamen auszudenken und alle einzeln anzulegen. Sie benötigen einen "Sammelbegriff", unter dem Sie alle Bücher einordnen können. Verwenden Sie dafür ein Array, ordnen Sie die einzelnen Buch-Objekte als Elemente ein.

Tipps zu 4

Orientieren Sie sich an Übung 3. Das Prinzip ist durchaus ähnlich. Die Funktion, die wir dort zur Ausgabe geschrieben haben, ist eine gute Grundlage für die jetzt benötigte Methode. Überlegen Sie, welchem Objekt Sie diese Methode geben müssen, damit sie in einem Zug über alle Links läuft. Denken Sie an Bedeutung und Zweck von this.

Die Form, die Sie für die Auflistung wählen, steht Ihnen natürlich frei. Ich empfehle, für jeden Link eine eigene Definition-List zu nutzen mit dem verlinkten Titel im dt-Element und den anderen Angaben nacheinander in dd-Elementen. So habe ich es in den Lösungsvorschlägen gemacht.

Tipps zu 5

Übernehmen Sie die Objektstruktur aus Übung 4, die wird auch hier gebraucht, anders soll sich nur die Anzeige gestalten. Sie können die bestehende Anzeigefunktion so ändern, dass sie nicht mehr unbesehen der Reihe nach ausgibt, sondern thematisch. Geschickter ist es eventuell, dem einzelnen Linkobjekt eine eigene Methode für das Anzeigen (oder Aufbereiten des zughörigen HTML-Codes als String) zu geben.

Denken Sie daran, dass Sie sich wahrscheinlich merken müssen, welche Links bereits erledigt sind; sehen Sie eine Eigenschaft erledigt vor. Um die bestehenden Konstruktor-Funktionen nicht ändern zu müssen, erinnern Sie sich bitte einmal an prototype.

4.4 Lösungen

Lösung zu 1

Der new-Operator fehlt, das ist die sprichwörtliche kleine Ursache mit großer Wirkung. In der angegeben Form wurde kein Objekt definiert , sondern die Funktion Heft() einfach nur aufgerufen, der Variablen meinHeft würde in dieser Schreibweise der Rückgabewert der Funktion zugewiesen. Da sie aber keinen Wert zurückgibt, ist meinHeft anschließend undefined, und meinHeft.Seiten gibt es gar nicht. Korrekt wäre also

meinHeft = new Heft(15);

Lösung zu 2

Es wird zwar ein neues Objekt definiert, aber die Konstruktor-Funktion legt keine Eigenschaft Umschlag dafür an. Das hätte sie mit this tun müssen:

   this.Umschlag = Umschlag;

Lösung zu 3

Die nachfolgende HTML-Seite ist eine mögliche Lösung für die Aufgabenstellung, eine größere Anzahl von Büchern aufzulisten.

Hinweis

Einen Hinweis zum Verständnis meines Lösungsvorschlags muss ich noch anbringen, bevor Sie sich in ihn vertiefen: Wenn Sie HTML-Code per JavaScript generieren, ist es sinnvoll, nicht viele document.write()-Anweisungen hintereinander zu schreiben, sondern den Code in einem String zusammenzufassen und dann mit nur einem document.write() auszugeben. Das beschleunigt die Ausführung. Solche Strings können dann natürlich recht lang werden. Um sie zusammenzubauen, verwende ich gern folgende Form:

var Aus = '';                  /* initialisieren */
Aus += 'viel, viel HTML-Code'; /* HTML-Code      */
Aus += '...';                  /* zusammensetzen */
Aus += '...';
document.writeln(Aus);         /*ausgeben        */

Den Operator += finde ich dafür sehr praktisch. Er ist eine Kurzform, die Schreibaufwand verringert und Übersichtlichkeit erhöht. Die folgen Anweisungen tun dasselbe:

Beispiel

Aus = Aus + eine_Variable;
Aus+= eine_Variable;;

Die Konstruktor-Funktionen in der Lösung kennen Sie schon. Neu ist das Array meineBuecher[], in dem sich die Objekte für die einzelnen Bücher als Elemente wiederfinden. Damit kann man so eine Auflistung, wie Sie sie gleich sehen werden, ganz einfach realisieren; man kennt mit meineBuecher.length die Anzahl der Elemente, kann in einer Schleife nacheinander jedes einzeln ansprechen.

<html>
<head>
<title>Alle meine Bücher</title>
<script language="JavaScript" type="text/javascript">
<!--
/* * * Vorbereitende Funktionen * * */
// Konstruktorfunktion fuer Einbaende
function Einband(pFarbe, pArt)
{
   this.Farbe  = pFarbe;
   this.Art    = pArt;
}
// Konstruktorfunktion fuer Buecher
function Buch(pTitel, pVerlag, pSeiten, pFarbe, pArt)
{
   this.Titel       = pTitel;
   this.Verlag      = pVerlag;
   this.Seiten      = pSeiten;
   this.Einband     = new Einband(pFarbe, pArt);
}
// fuegt als Methode einer Liste von Buechern neue hinzu
function hinzufuegen(pTitel, pVerlag, pSeiten, pFarbe, pArt)
{
   this[this.length] = new Buch(pTitel, pVerlag,
                           pSeiten, pFarbe, pArt);
}
/* * * Beginn der Abarbeitung * * */
// erst mal nachsehen, ob der Browser Arrays kennt
if (window.Array)
{
   // eine "Liste" fuer all meine Buecher anlegen
   meineBuecher = new Array();
   // Methode fuer das Hinzufuegen definieren
   meineBuecher.hinzufuegen = hinzufuegen;
   // einzelne Buecher eintragen
   // hier muss ich spaeter neue einfuegen
   with (meineBuecher)
   {
      hinzufuegen("JavaScript Workshop",
                  "Addison-Wesley", 300,
                  "gelb", "Taschenbuch");
      hinzufuegen("JavaScript 1.2",
                  "Addison-Wesley", 500,
                  "weiß", "gebunden");
   }
}
else
  // zum Abschluss noch der Hinweis
  // fuer Leute mit aelteren Browsern:
  alert('Ihr Browser ist recht alt, kennt kein Array!');
// -->
</script>    
</head>
<body>
<h1>Alle meine Bücher</h1>
<script language="JavaScript" type="text/javascript">
<!--
// diese Funktion generiert eine Auflistung aller Buecher
function zeigeBuecher()
{
   var Aus = '<ol>';
   for (var i = 0; i < meineBuecher.length; i++)
   {
      Aus += '<li>' + meineBuecher[i].Titel;
      Aus += '<ul>';
      Aus += '<li>' + meineBuecher[i].Verlag + '</li>';
      Aus += '<li>ca. : ' + meineBuecher[i].Seiten;
      Aus += ' Seiten</li>';
      Aus += '<li>' + meineBuecher[i].Einband.Art + '\/';
      Aus += meineBuecher[i].Einband.Farbe + '</li>';
      Aus += '</ul>';
   }
   Aus+= '</ol>\n';
   Aus+= '<p>Ich besitze ';
   Aus += meineBuecher.length + ' Bücher.</p>';
   return Aus;
}
// existiert meineBuecher ueberhaupt?
if (window.meineBuecher)
   var Ausgabe = zeigeBuecher();
else
   var Ausgabe = '<p>Mit diesem Browser funktioniert '
               + 'das hier leider nicht!<p>';
document.writeln(Ausgabe);
// -->
</script>
<noscript>
Ohne JavaScript geht hier nix!
</noscript>
</body>
</html>

Im Ergebnis erhalten Sie eine HTML-Seite, die abhängig von den Büchern, die Sie eingetragen haben, etwa das hier enthält:

Alle meine Bücher
1.JavaScript Workshop
  · Addison-Wesley
  · ca. : 300 Seiten
  · Taschenbuch/gelb
2.JavaScript 1.2
  · Addison-Wesley
  · ca. : 500 Seiten
  · gebunden/weiß
Ich besitze 2 Bücher.

uebung0403.html -

Lösung zu 4

Die nachfolgende HTML-Seite ist eine mögliche Lösung: Die Methode zeigen() übernimmt die Auflistung; sie gehört zum Array meineLinks[]. Das Problem der fehlenden Screenshots wurde gelöst, indem der Konstruktor:Funktion ein leerer String übergeben wird, wenn keine Grafik vorhanden ist. Die Funktion setzt in dem Fall den Wert der Eigenschaft Screenshot auf den Dateinamen der Ersatzgrafik.

<html>
<head>
<title>meine Links</title>
<script language="JavaScript" type="text/javascript">
<!--
/* * * Vorbereitende Funktionen * * */
// Konstruktorfunktion fuer Links
function macheLink(pTitel, pAdresse, pAutor, pThema,
                   pAnmerkung, pScreenshot)
{
   this.Titel      = pTitel;
   this.Adresse    = pAdresse;
   this.Autor      = pAutor;
   this.Thema      = pThema;
   this.Anmerkung  = pAnmerkung;
   // ist Dateiname fuer Screenshot angegeben?
   if (pScreenshot.length > 0)
      this.Screenshot = pScreenshot;
   else
      // Alternativgrafik
      this.Screenshot = 'keinbild.gif';
}
// fuegt als Methode einer Liste von Links neue hinzu
function hinzufuegen(pTitel, pAdresse, pAutor, pThema,
                     pAnmerkung, pScreenshot)
{
   this[this.length] = new macheLink(pTitel, pAdresse, pAutor,
                           pThema, pAnmerkung, pScreenshot);
}
// diese Funktion generiert als Methode eine
// Auflistung aller Links
function zeigen()
{
   var Aus = '';
   for (var i = 0; i < meineLinks.length; i++)
   {
      Aus += '<dl>';
      Aus += '<dt>';
      Aus += '<a href="' + this[i].Adresse + '">';
      Aus += '<img src="images/';
      Aus += this[i].Screenshot;
      Aus += '" width="110" height="83" alt="'
      Aus += this[i].Titel
      Aus += '" border="0" align="middle" ';
      Aus += 'hspace="2" vspace="1">';
      Aus += this[i].Titel + '</a></dt>';
      Aus += '<dd>' + this[i].Anmerkung + '</dd>';
      Aus += '<dd>' + this[i].Autor + '</dd>';
      Aus += '</dl>';
   }
   return Aus;
}
/* * * Beginn der Abarbeitung * * */
if (window.Array)
{
   // eine "Liste" fuer alle Links anlegen
   meineLinks = new Array();
   // Methode fuer das Hinzufuegen definieren
   meineLinks.hinzufuegen = hinzufuegen;
   // Methode fuer Anzeige definieren
   meineLinks.zeigen = zeigen;
   // hier muss ich spaeter neue einfuegen
   with (meineLinks)
   {
      hinzufuegen('JavaScript-Informationen',
         'http://mintert.com/javascript/',
         'S. Mintert',
         'JavaScript',
         'Buch, Chronologie von JavaScript, Standards etc.',
         'javascriptmintert.gif');
      hinzufuegen('JavaScript-Notizen',
         'http://netz-notizen.de/javascript',
         'Ch. Kühnel',
         'JavaScript',
         'Beispiele, Tipps zu JavaScript und DHTML',
         'javascriptnotizen.gif');
      hinzufuegen('HTML 4',
         'http://www.w3.org/TR/html4/',
         'W3C',
         'HTML',
         'Spezifikation HTML 4',
         '');
   }
}
else
  // zum Abschluss noch der Hinweis für
  // Leute mit aelteren Browsern:
  alert('Ihr Browser ist recht alt, kennt kein Array!');
// -->
</script>
</head>
<body>
<h1>meine Links</h1>
<script language="JavaScript" type="text/javascript">
<!--
// existiert meineLinks ueberhaupt?
if (window.meineLinks)
   var Ausgabe = meineLinks.zeigen();
else
   var Ausgabe = '<p>Mit diesem Browser funktioniert ' +
                 'das hier leider nicht!<p>';
document.writeln(Ausgabe);
// -->
</script>
<hr>
</body>
</html>

Im Lösungsvorschlag auf der beiliegenden CD finden Sie noch mehr eingetragene Links, die hier natürlich nicht alle abgedruckt werden können.

uebung0404.html -

Lösung zu 5

Meinen Vorschlag zur Lösung finden Sie hier nur in Auszügen. Alles, was bereits bekannt ist und unverändert übernommen werden kann, deute ich lediglich an. Sie wollen ja nicht dasselbe immer wieder lesen. Auf der CD gibt es den Code selbstverständlich vollständig.

// Konstruktorfunktion fuer Links
function macheLink(Titel, Adresse, Autor, Thema,
                   Anmerkung, Screenshot)
{ /* kennen Sie schon */ }
// fuegt als Methode einer Liste von Links neue hinzu
function hinzufuegen(Titel, Adresse, Autor, Thema,
                     Anmerkung, Screenshot)
{ /* kennen Sie schon */ }

Die folgende Funktion ist neu. Um unabhängig von der Reihenfolge der Ausgabe zu sein, treffen wir Vorbereitungen, jedem Eintrag eine eigene Anzeigemethode zu geben; die Aufbereitung eines Strings mit HTML-Code erfüllt diesen Zweck natürlich auch sehr gut.

// bereitet Ausgabe fuer einen
// einzelnen Eintrag vor
function zeigeEintrag()
{
   var Aus = '';
   Aus += '<dl>';
   Aus += '<dt>';
   Aus += '<a href="' + this.Adresse + '">';
   Aus += '<img src="images/';
   Aus += this.Screenshot;
   Aus += '" width="110" height="83" alt="'+this.Titel;
   Aus += '" border="0" align="middle" ';
   Aus += 'hspace="2" vspace="1">';
   Aus += this.Titel + '</a></dt>';
   Aus += '<dd>' + this.Anmerkung + '</dd>';
   Aus += '<dd>' + this.Autor + '</dd>';
   Aus += '</dl>';
   return Aus;
}

Neu ist auch die folgende Funktion. Hier werden die Einträge durchforstet, um gleiche Themen zu finden. Das Prinzip ist ganz einfach: Das erste Thema wird als auszugebendes gesetzt, alle weiteren Einträge geprüft, ob zu diesem Thema gehörig. Bereits ausgegebene Einträge werden gekennzeichnet, indem die Eigenschaft erledigt auf true gesetzt wird. Sind alle Einträge geprüft, beginnen wir an der Stelle, wo das letzte Thema gesetzt wurde, mit dem Suchen nach einem neuen, noch nicht ausgegebenen Thema. Irgendwann sind wir am Ende angekommen.

// zeigt thematisch geordnet
function zeigeThematisch()
{
   // gerade aktuelles Thema initialisieren
   var AusgabeThema = '';
   // naechstes Thema suchen
   for (var i = 0; i < this.length; i++)
      // ist Thema anders u. Link noch n. ausgegeben?
      if ((this[i].Thema != AusgabeThema) &&
          !this[i].erledigt)
      {
         // aktuelles Thema setzen
         AusgabeThema = this[i].Thema;
         // Themenüberschrift ausgeben
         document.writeln('<h2>' + AusgabeThema + '</h2>');
         // nach weiteren Links zum selben Thema suchen
         for (var j = i; j < this.length; j++)
            // gehoert zum aktuellen Thema?
            if (this[j].Thema == AusgabeThema)
            {
               // Link aufbereiten und ausgeben
               document.writeln(this[j].zeigeEintrag());
               // dieser Link ist erledigt
               this[j].erledigt = true;
            }
      }
}
/* * * Beginn der Abarbeitung * * */
...

Das Anlegen der Objekte müssen wir nicht ändern. Lediglich auf die Methode zeigen(), die der Reihe nach ausgibt, könnten wir jetzt verzichten.

Aber unsere Objekte brauchen zusätzliche Methoden, und dann war da ja noch die Eigenschaft erledigt. Zum Glück können wir das alles auch noch an dieser Stelle erledigen. Für erledigt nutzen wir prototype und geben allen Objekten auf einen Schlag die neue Eigenschaft mit dem Wert false.

// allen Elementen nachtraeglich Eigenschaft erledigt geben
macheLink.prototype.erledigt = false;
macheLink.prototype.zeigeEintrag = zeigeEintrag;
meineLinks.zeigeThematisch = zeigeThematisch;

Der Script-Teil im body ist nun nur noch eine Kleinigkeit:

<script language="JavaScript" type="text/javascript">
<!-
// existiert meineLinks ueberhaupt?
if (window.meineLinks)
   meineLinks.zeigeThematisch();
else
{
   var Ausgabe = '<p>Mit diesem Browser funktioniert ' +
                 'das hier leider nicht!<p>';
   document.writeln(Ausgabe);
}
// -->
</script>

uebung0405.html -

1 Der englische Begriff, "Keyword" ist in der Programmierung gebräuchlich, verzichten wir deshalb darauf, daraus ein "Schlüsselwort" zu machen. [zurück]

Linkwerk
screeneXa