Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 <<   zurück
JavaScript und AJAX von Christian Wenz
Das umfassende Handbuch
Buch: JavaScript und AJAX

JavaScript und AJAX
839 S., mit DVD, 39,90 Euro
Rheinwerk Computing
ISBN 3-89842-859-1
gp Kapitel 13 Objekte und Arrays
  gp 13.1 Array-Erweiterungen
    gp 13.1.1 Einfügen, nicht anfügen
    gp 13.1.2 Anfügen und löschen
    gp 13.1.3 Array-Elemente mischen
    gp 13.1.4 Sortieren
  gp 13.2 Eigene Objekte
    gp 13.2.1 Allgemeines
    gp 13.2.2 Methoden definieren
    gp 13.2.3 Eigene Sortiermethode
    gp 13.2.4 Eigene Sortiermethode, Teil 2
    gp 13.2.5 Zusammenfassung
    gp 13.2.6 Platzsparende Notation
  gp 13.3 JavaScript-Objekte erweitern


Rheinwerk Computing

13.2 Eigene Objekte  downtop

In diesem Abschnitt sollen einige Array-Funktionalitäten der aktuellen JavaScript-Version 1.2 für ältere Browser (und die meisten Versionen des Internet Explorer) nachgebildet werden. Dazu ist es nötig, eigene Objekte zu erstellen.

In der Praxis wird diese Technik nur bei größeren Projekten verwendet und in solchen Fällen, in denen der Funktionsumfang der üblichen Variablen und Arrays nicht mehr ausreicht.


Rheinwerk Computing

13.2.1 Allgemeines  downtop

In ganz alten JavaScript-Versionen (und -Browsern) war es üblich, mit der folgenden Hilfsfunktion Arrays zu erstellen:

function MakeArray(n) {
   for (var i=0; i<n; i++) {
      this[i] = 0;
   }
   this.length = n;
}

Hier die kurze Erklärung für den obigen Code: Mit dem Schlüsselwort this wird ja normalerweise auf das aktuelle Objekt zugegriffen, im Allgemeinen auf das aktuelle Fenster oder Formularelement. Wird diese Funktion jedoch als so genannte Konstruktorfunktion für ein Objekt verwendet, also mit new MakeArray() aufgerufen, so bezeichnet this die aktuelle Instanz des Objekts. Somit wird durch die wiederholte Ausführung des Befehls this[i]=0 die Instanz als Array deklariert und jedes Array-Element mit null vorbelegt. Von besonderer Bedeutung ist die Zeile this.length = n. Hierdurch wird die Eigenschaft length des Objekts auf n gesetzt und nicht etwa die Länge eines Arrays (Anzahl der Elemente) festgelegt. Standardmäßig hat ja ein Array unbegrenzt viele Elemente, und das ist auch hier so. Da es sich hierbei aber um kein »echtes« Array handelt, sondern um ein eigenes Objekt, hat die Eigenschaft length nichts mit der Anzahl der Elemente des Objekts zu tun. Wird also ein Element an das Array angefügt, so wird length nicht automatisch angepasst; das muss man also selbst übernehmen. Aus diesem Grund sollten Sie bei der Implementierung für zusätzliche Funktionalität von MakeArray() sehr vorsichtig sein.


Rheinwerk Computing

13.2.2 Methoden definieren  downtop

Fast genauso einfach wie die Definition von Objekteigenschaften ist die Definition von Objektmethoden. Auch hier ist der this-Operator wieder von Bedeutung. Beim Setzen einer Methode verwendet man folgende Syntax im Konstruktor:

this.methode = funktion;

Bei jedem Aufruf der Methode wird funktion() ausgeführt, und innerhalb von funktion() kann man mit this auf die verwendete Instanz des Objekts zugreifen. Beachten Sie, dass auch hier die Klammern fehlen – denn funktion ist eine Referenz auf die Funktion funktion(). Und natürlich würden auch hier wieder anonyme Funktionen in Frage kommen.

Als Beispiel soll die Methode toString() implementiert werden. Dazu muss zunächst MakeArray() folgendermaßen geändert werden:

function MakeArray(n) {
   for (var i=0; i<n; i++) {
      this[i] = 0;
   }
   this.length = n;
   this.toString = arraytoString;
}

Die Funktion arraytoString() gibt die Elemente des Arrays, durch Kommata voneinander getrennt, aus. Dazu werden einfach alle Elemente in this abgefragt und miteinander verkettet.

function arraytoString() {
   var returnstring = "";
   for (var i=0; i<this.length-1; i++) {
      returnstring += this[i] + ",";
   }
   returnstring += this[this.length-1];
   return returnstring;
}

Analog kann man auch die Funktion push() nachbilden: Alle übergebenen Parameter werden an das Array angehängt. Abschließend muss die Eigenschaft length noch angepasst werden.

function MakeArray(n) {
   for (var i=0; i<n; i++) {
      this[i] = 0;
   }
   this.length = n;
   this.toString = arraytoString;
   this.push = arraypush;
}
function arraypush() {
   for (var i=0; i<arraypush.arguments.length; i++) {
      this[this.length+i] = arraypush.arguments[i];
   }
   this.length += arraypush.arguments.length;
}

Rheinwerk Computing

13.2.3 Eigene Sortiermethode  downtop

Das Sortieren war bei JavaScript Version 1.0 noch nicht möglich. Erstellt man jedoch ein eigenes Objekt, kann man diese Funktionalität auch nachbilden. Die Einrichtung einer Methode ist nicht schwer, Sie müssen nur eine Zeile in die Konstruktorfunktion einfügen:

function MakeArray(n) {
   for (var i=0; i<n; i++) {
      this[i] = 0;
   }
   this.length = n;
   this.toString = arraytoString;
   this.push = arraypush;
   this.sort = arraysort;
}

Bei der Implementierung der Funktion arraysort() muss man sich zunächst für einen geeigneten Sortieralgorithmus entscheiden. Am leichtesten tut man sich – zumindest meiner Meinung nach – mit dem Bubblesort-Algorithmus. Der benötigt zwar eine quadratische Laufzeit (unter diesem Aspekt gibt es bessere Algorithmen), aber er ist dafür besonders einfach zu implementieren. Das Verfahren funktioniert wie folgt: Zwei nebeneinanderliegende Elemente des Arrays werden miteinander verglichen. Haben diese Elemente schon die richtige Reihenfolge (ist das »linke« also kleiner als das »rechte«), passiert nichts, ansonsten tauschen die beiden Elemente ihren Platz. Sodann werden das jetzt rechts liegende Element und das Element rechts daneben betrachtet. Auf diese Weise wird das gesamte Array durchlaufen, und das geschieht so oft, bis das Array korrekt sortiert ist.

Das folgende Ablaufschema zeigt exemplarisch die Sortierung. Elemente, die vertauscht werden, sind jeweils unterstrichen:

3142®1342®1324®1234

Zunächst muss man sich überlegen, wie man zwei Elemente – oder vereinfacht gesagt, zwei Variablen – vertauscht. Der folgende Code funktioniert leider nicht:

var a, b;
function tausche(){
   a = b;
   b = a;
}

Nachdem die Zuweisung a = b ausgeführt worden ist, enthalten a und b denselben Wert; der ursprüngliche Wert von a ist verloren. Um nun wirklich vertauschen zu können, verwendet man eine Hilfsvariable, in der man den ursprünglichen Wert von a abspeichert. Dann wird a der Wert von b zugewiesen, und b erhält den ursprünglichen Wert von a – aus der Hilfsvariablen:

var a, b;
function tausche() {
   var hilfsvariable = a;
   a = b;
   b = hilfsvariable;
}

Die Implementierung des Bubblesort-Algorithmus ist dann nicht weiter schwierig. Man darf sich nur beim Vertauschen der Array-Elemente nicht vertun und muss immer fleißig this verwenden!

function arraysort() {
   var sortiert = false;  //Überprüfung, ob sortiert
   while (!sortiert) {
      sortiert = true;
      for (var i = 0; i < this.length – 1; i++) {
         if (this[i] > this[i+1]) {
            sortiert = false;
            hilfsvariable = this[i];
            this[i] = this[i+1];
            this[i+1] = hilfsvariable;
         }
      }
   }
}

Beachten Sie, dass die Variable i von 0 bis this.length-2 läuft, da das Array-Element an der Position i mit dem nachfolgenden Element verglichen wird – und das Element an der Position this.length-1 hat keinen Nachfolger.


Rheinwerk Computing

13.2.4 Eigene Sortiermethode, Teil 2  downtop

In Hinblick auf das Beispiel mit dem Kartenspiel wäre es natürlich noch schön, wenn man wieder die Sortiermethode selbst angeben könnte. Auch dies kann man mit JavaScript erreichen. Zunächst muss man die Funktion arraysort() leicht modifizieren:

function arraysort() {
   var sortiert = false;  //Überprüfung, ob sortiert
   while (!sortiert) {
      sortiert = true;
      for (var i=0; i<this.length-1; i++) {
         if (groesser(this[i], this[i+1],
            arraysort.arguments[0])){
            sortiert = false;
            hilfsvariable = this[i];
            this[i] = this[i+1];
            this[i+1] = hilfsvariable;
         }
      }
   }
}

Die Funktion groesser(a, b, arg) gibt zurück, ob a größer als b ist; arg enthält einen an die Funktion arraysort() übergebenen Parameter (wozu der nützlich ist, wird gleich erläutert). Im Beispiel aus dem vorigen Abschnitt würde diese Funktion folgendermaßen aussehen:

function groesser(a, b, arg) {
   return (a > b);
}

Unser Ziel soll es jedoch sein, eine beliebige Funktion an arraysort() bzw. an die Methode sort() des MakeArray-Objekts zu übergeben. Aufgrund der Einschränkungen von JavaScript muss der Name der Sortierfunktion als Zeichenkette übergeben werden. Der Rest ist dann gar nicht mehr so schwierig. Mittels eval() wird die Sortierfunktion mit zwei Array-Elementen als Parametern aufgerufen und das Ergebnis ausgewertet. Zur Erinnerung: Nur wenn das Ergebnis größer als 0 ist, ist der erste Parameter größer als der zweite. Zusätzlich muss natürlich noch überprüft werden, ob überhaupt ein Parameter an arraysort() übergeben worden ist. Sollte das nicht der Fall sein, wird ein alphanumerischer Vergleich mit dem >-Operator durchgeführt.

function groesser(a, b, arg) {
   if (arg == null) {
      return (a>b);
   } else {
      var erg = eval(arg + "(\"" + a + "\", \"" + b +
      "\")");
      return (erg > 0);
   }
}

Rheinwerk Computing

13.2.5 Zusammenfassung  downtop

Im Folgenden finden Sie eine Anwendung für das MakeArray-Objekt. Das Kartenblatt wird initialisiert, in vier Teile aufgeteilt (beispielsweise für eine Partie Schafkopf zu viert) und (sortiert) ausgegeben.

Die Funktion MakeArray() (beziehungsweise, um exakt zu sein: der Klassenkonstruktor – derjenige Code, der bei der Instanziierung der Klasse aufgerufen wird) wurde für dieses Beispiel leicht angepasst, so dass man als Parameter nicht die Größe des Arrays übergibt, sondern die anfänglichen Array-Elemente selbst.

<html>
<head>
<title>Karten spielen mit JavaScript</title>
<script type="text/javascript"><!--
//Funktionen des MakeArray-Objekts
function MakeArray(){
   for (var i = 0; i < MakeArray.arguments.length; i++) {
      this[i] = MakeArray.arguments[i];
   }
   this.length = MakeArray.arguments.length;
   this.toString = arraytoString;
   this.push = arraypush;
   this.sort = arraysort;
}
//Methoden
function arraytoString() {
   var returnstring = "";
   for (var i=0; i<this.length-1; i++) {
      returnstring += this[i] + ",";
   }
   returnstring += this[this.length-1];
   return returnstring;
}
function arraypush() {
   for (var i=0; i<arraypush.arguments.length; i++) {
      this[this.length+i] = arraypush.arguments[i];
   }
   this.length += arraypush.arguments.length;
}
function arraysort() {
   var sortiert = false;  //Überprüfung, ob sortiert
   while (!sortiert) {
      sortiert = true;
      for (var i=0; i<this.length-1; i++) {
         if (groesser(this[i], this[i+1],
            arraysort.arguments[0])) {
            sortiert = false;
            hilfsvariable = this[i];

            this[i] = this[i+1];
            this[i+1] = hilfsvariable;
         }
      }
   }
}
function groesser(a, b, arg) {
   if (!arg) {
      return (a>b);
   } else {
      var erg = eval(arg + "(\"" + a + "\", \"" + b +
      "\")");
      return (erg > 0);
   }
}
// *** Das eigentliche Programm ***
//Hilfsvariablen für die Kartenbezeichnungen
var kartenname = new MakeArray("Zwei", "Drei", "Vier", "Fünf", "Sechs", 
"Sieben", "Acht", "Neun", "Zehn", "Bube", "Dame", "König", "As");
var farben = new MakeArray("Herz", "Karo", "Pik", "Kreuz");
//Initialisierung des Kartenarrays
var cards = new MakeArray();
for (var i=0; i<13; i++) {
   for (var j=0; j<4; j++) {
      karte = kartenname[i] + " " + farben[j];
      cards.push(karte);
   }
}
//Karten mischen

//Karten auf vier Personen verteilen
var hand1 = new MakeArray();
var hand2 = new MakeArray();
var hand3 = new MakeArray();
var hand4 = new MakeArray();
for (i=0; i<=12; i++) {
   hand1.push(cards[i]);
}
for (i=13; i<=25; i++) {
   hand2.push(cards[i]);
}
for (i=26; i<=38; i++) {
   hand3.push(cards[i]);
}
for (i=39; i<=51; i++) {
   hand4.push(cards[i]);
}
//Karten sortieren
hand1.sort("cardsort");
hand2.sort("cardsort");
hand3.sort("cardsort");
hand4.sort("cardsort");

//Sortierfunktion
function cardsort(a, b) {
   var wert_a = a.substring(0, a.indexOf(" "));
   var wert_b = b.substring(0, b.indexOf(" "));
   var index_a = –1; var index_b = –1;
   for (var i=0; i<kartenname.length; i++) {
      if (kartenname[i] == wert_a) {
         index_a = i;
      }
      if (kartenname[i] == wert_b) {
         index_b = i;
      }
   }
   if (index_a > index_b) {
      return 1;
   } else if (index_a < index_b) {
      return –1;
   }
   var farbe_a = a.substring(a.indexOf(" ")+1,
      a.length);
   var farbe_b = b.substring(b.indexOf(" ") + 1,
      b.length);
   return (farbe_a > farbe_b) ? 1 : 0;
}
//--></script>
</head>
<body>
<h1>Karten spielen mit JavaScript</h1>
<script type="text/javascript"><!--
function br() {
   return "<" + "br" + " />";
}
document.write("Hand 1: " + hand1.toString() + br());
document.write("Hand 2: " + hand2.toString() + br());
document.write("Hand 3: " + hand3.toString() + br());
document.write("Hand 4: " + hand4.toString() + br());
//--></script>
</body>
</html>

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 13.3     Die an vier Leute verteilten Karten, sortiert


Rheinwerk Computing

13.2.6 Platzsparende Notation  toptop

Auch bei Objekten gibt es – ähnlich wie bei Arrays – eine platzsparende Notation. Hier ein Beispiel für das handgeschriebene Array, zwar ohne Funktionalität im Konstruktor, aber mit einigen Methoden:

var a = {
   "length": 0,
   "toString": function () {
      var returnstring = "";
      for (var i=0; i<this.length-1; i++) {
         returnstring += this[i] + ",";
      }
      returnstring += this[this.length-1];
      return returnstring;
   },
   "push": function() {
      for (var i=0; i<arraypush.arguments.length; i++) {
         this[this.length+i] = arraypush.arguments[i];
      }
      this.length += arraypush.arguments.length;
   }
};

Sie sehen also: Mit den geschweiften Klammern zeigen Sie an, dass ein Objekt vorliegt. Eigenschaften (oder Methoden) und ihre Werte (oder Implementierungen werden durch Doppelpunkte voneinander getrennt. Auch diese Kurznotation werden Sie an späterer Stelle wiederfinden: in Kapitel 18 unter dem Namen »JSON«.

 <<   zurück
  
  Zum Rheinwerk-Shop
Neuauflage: JavaScript
Neuauflage: JavaScript
bestellen
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: jQuery






 jQuery


Zum Rheinwerk-Shop: Einstieg in JavaScript






 Einstieg in JavaScript


Zum Rheinwerk-Shop: Responsive Webdesign






 Responsive Webdesign


Zum Rheinwerk-Shop: Suchmaschinen-Optimierung






 Suchmaschinen-
 Optimierung


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern