Objekte
JavaScript gehört, als moderne Sprache, zu den objektorientierten Programmiersprachen (OOP). Zugegriffen wird von JavaScript also in der Regel auf Objekte.
Ein Objekt ist der Versuch, die reale Welt in einer Programmiersprache abzubilden. Eine Klasse definiert ein solches Objekt. Die Klasse Auto könnte also alle Eigenschaften und Verhaltensweisen von Automobilen im Allgemeinen beschreiben. Klassen sind abstrakte Definitionen.
Um ein konkretes Auto zu bezeichnen, wird von der allgemeinen Klasse eine Instanz – die man sich zunächst als Kopie der Klasse vorstellen kann – gebildet. Diese Instanz kann nun mit den Eigenschaften eines ganz bestimmten Fahrzeugs spezifiziert werden (z.B. die Zulassungsnummer, Farbe, Marke etc.). Für jedes konkrete Auto würde eine solche Instanz angelegt werden.
Objekte bestehen aus zwei Teilen.
1) Der erste Teil besteht aus Variablen, die die Eigenschaften eines Objektes festlegen. In unserem Beispiel könnte die Klasse Auto eine Variable RaederAnzahl haben, die als Konstante mit 4 belegt ist. Weitere Variablen die ein Auto beschreiben, wie Farbe oder Zulassungsnummer, würden erst belegt werden, wenn eine Insatnz der Klasse erzeugt wird. Diese Eigenschaften sind individuell. Zwar hat jedes Auto zwingend eine Farbe (in der Klasse wird eine entsprechende Variable vereinbart), welche Farbe das ist, kann aber nur für jedes konkrete Fahrzeug festgelegt werden (die Instanz belegt die Variable mit den individuellen Eigenschaften).
2) Im zweiten Teil bestehen Objekte aus sogenannten Methoden. Diese legen fest, was man mit dem Objekt anstellen kann. Methoden sind Funktionen, die fest an das Objekt gebunden sind. Zieht ein Fahrer mit seinem PKW um, so könnte eine Methode ummelden() aufgerufen werden. Diese Funktion würde zum Beispiel die Objektvariable Zulassungsnummer auf einen neuen Wert setzen.
Objekte können andere Objekte als Eigenschaften enthalten, wie weiter unten gezeigt wird. So könnte es ein Objekt Räder geben, das Durchmesser, Bereifung etc. als Eigenschaft enthält. Die Klasse Auto würde wiederum vier Räder als Eigenschaften beinhalten.
Das Konzept der Objektorientierung kann hier nur sehr oberflächlich in seinen Grundzügen dargestellt werden, soweit es für das Verständnis von JavaScript unbedingt erforderlich ist. Es bietet aber sehr viel mehr als hier angesprochen werden kann.
Aufruf von Objekten
Eine neue Instanz von einer Klasse wird durch das Schlüsselwort new erzeugt und bekommt einen Namen, indem man die Instanz zunächst wie eine Variable behandelt:
var d = new Date();
var mitarbeiter = new Array();
In der zweiten Zeile des Beispiels wurde eine Instanz der Klasse Array erzeugt und mitarbeiter genannt.
Um mit dem Objekt arbeiten zu können (Ändern einer Eigenschaft oder Aufruf einer Methode) spreche ich es über den Namen der Instanz an. Damit ist auch immer klar welches Auto gemeint ist.
Um eine Eigenschaft zu ändern oder auszulesen, rufe ich das Objekt und den Namen der Eigenschaft (Variablen) auf indem ich beide mit einem Punkt zusammensetze:
x = mitarbeiter.length;
In x bekomme ich so die Länge meiner Mitarbeiterliste, da length eine Eigenschaft des Objektes ist die in dieser Variablen gespeichert ist. Ebenso beim Aufruf einer Methode (Funktion):
document.write("Hallo");
Das Objekt heißt hier document und stellt eine Methode zur Verfügung, die write() heißt. Die obere Anweisung ruft also diese Methode auf.
In den meisten Situationen wird man nicht selbst Objekte erzeugen (obwohl das möglich ist), sondern auf die Objekte zugreifen, die JavaScript zur Verfügung stellt, und sie verändern. Einige Instanzen wie document, window oder location werden nämlich automatisch erzeugt, wenn ein HTML-Dokument im Browser aufgerufen wird.
Beispiel: Date-Objekt
Sehen wir uns einmal die vordefinierte Klasse Date an. Mit ihr ist es möglich das Datum und die Uhrzeit des Clients (nicht des Servers!) abzufragen. Bestimmte Eigenschaften der Instanz von Date, hier mit dem Namen datetime werden also mit den Systemeinstellungen des Clients beim Erzeugen der Instanz mit new automatisch belegt.
var datetime = new Date();
Es besteht aber auch die Möglichkeit sich mit dieser Klasse selbst ein Datum zu definieren.
var myDate = new Date(2001,5,18); //Jahr, Monat, Tag
oder noch genauer
var myDatetime = new Date(2001,5,18,10,30,0); //Jahr, Monat, Tag, Stunde, Minute, Sekunde
Achtung! Die obrige Instanz wird für das Datum 16.6.2001 erstellt, da JavaScript die Monate von 0-11 zählt. Die Tage (bei der Funktion getDay()) fangen ebenfalls bei 0 an (=Sonntag) und gehen bis 6 (=Samstag).
Das Date-Objekt belegt also beim Erzeugen der Instanz verschiedene Variablen als seine Eigenschaften. Beim Date-Objekt können diese Eigenschaften aber nicht direkt beeinflusst werden. Dafür bietet das Objekt eine Reihe von Methoden, mit denen auf das Objekt und seine Eigenschaften zugegriffen werden kann. Hier eine Auswahl davon:
Die Klasse Date | |||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Eigenschaften
(=Variablen) |
Keine auf die von aussen zugegriffen werden kann. | ||||||||||||||||||||||||||||||||||
Methoden
(=Funktionen) Auswahl |
|
Intern werden alle Datumswerte als Zahl, der seit dem 1.Januar 1970 verstrichenen Millisekunden gespeichert. Das hat den großen Vorteil, das man so mit verschiedenen Datumsangaben rechnen kann.
Um zu erfahren wieviel Tage seit dem 1.1.1990 bereits vergangen sind braucht man nur die Ausgabe der Millisekunden für das Datum und heute voneinander abziehen und durch 1000 (Millisekunden), durch 60 (Sekunden), durch 60 (Minuten) durch 24 (Stunden) teilen. Siehe hier Beispiel 10.
Sollten Sie die Methode getYear() verwenden wollen müssen Sie wissen, daß diese in verschiedenen Browsern unterschiedliche Ergebnisse liefert. D.h. einige Browser sind nicht Y2K sicher, da sie Jahreszahlen nur zweistellig ausgeben.
Seit JavaScript 1.3 werden Jahreszahlen immer in dem Format Jahreszahl-1900 ausgegeben. Hier einige Beispiele:
Wenn man unterstellen kann, daß keine Jahreszahlen zwischen 0 und 199 im eigenen Programm vorkommen, und das Programm in hundert Jahren vermutlich nicht mehr benutzt wird, kann man das Problem mit einer kleinen Funktion leicht umgehen:
function getYearY2K(d) {
var y = d.getYear();
if (y<200)
return y+1900;
else
return y;
}
(Die Funktion stammt aus: Christian Wenz: "JavaScript")
Browserweiche
Wer mit JavaScript entwickelt, wird Probleme bekommen mit Inkompatibilitäten zwischen verschiedenen Browsern und deren Versionen. Bitte pflegen Sie nicht die Unart Ihre Website für einen bestimmten Browser zu "optimieren". Durch Faulheit oder Arroganz gegenüber anderen Betriebssystemen oder Softwareherstellern verliert man schnell seine Kunden.
Um die Inkompatibilitäten zu vermeiden oder zu umgehen gibt es verschiedene Möglichkeiten:
Es ist möglich mit JavaScript etwas über den Browser, der die Seite interpretiert, zu erfahren. Dafür wird das Objekt navigator zur Verfügung gestellt. (Es ist tatsächlich ein JavaScript-Objekt und hat nichts mit der Software von Netscape zu tun!) Auf dieses Objekt kann direkt zugegriffen werden, ohne vorher eine Instanz zu erzeugen. Das würde auch keinen Sinn machen, da es immer nur einen Browser geben kann, der die Seite gerade interpretiert, also kann es von dieser Klasse sinnvoller Weise immer nur eine Instanz pro Browser(-fenster) geben.
Um nun einen Browser zu erkennen, kann man drei Eigenschaften des Objektes auslesen. Hier die Ausgaben von ein paar Mac-Browsern:
Explorer 5.0 | Navigator 4.5 | Opera (Mac Preview 3) | |
navigator.appName | Microsoft Internet Explorer | Netscape | Opera |
navigator.userAgent | Mozilla/4.0 (compatible; MSIE 5.0; Mac_PowerPC) | Mozilla/4.5 [de] (Macintosh; I; PPC) | Opera/5.0 (Macintosh;US;PPC) TP [en] |
navigator.appVersion | 4.0 (kompatibel; MSIE 5.0; Macintosh; I; PPC) | 4.5 [de] (Macintosh; I; PPC) | 5.0 (Macintosh;US;PPC) |
Welche Informationen Ihr Browser zur Verfügung stellt, können Sie mit dem Beispiel 11 testen.
Exkurs: Tatsächlich können Firmen, die sehr an Ihren Daten und Verhaltensweisen interessiert sind weil sie damit Geld verdienen, mit entsprechenden Methoden noch viel mehr über Sie bzw. Ihren Browser erfahren. Was das alles ist, könne Sie auf folgenden Seiten einmal testen: |
Was kann man nun damit anfangen? Das Feld appName sollte eigentlich die Unterscheidung zwischen den Browsern ermöglichen, doch frühe Versionen des Explorer haben auch Netscape als Namen angegeben (! warum?).
Bleibt also das userAgent Feld. Da bei JavaScript Groß- und Kleinschreibung eine Rolle spielt, wandeln wir den String mit der Funktion toLowerCase() der String-Klasse erst einmal in Kleinbuchstaben um. Dann können wir sichergehen, daß beim Testen die Ergebnisse nicht durch die Großschreibung verfälscht werden.
var agent = navigator.userAgent.toLowerCase();
Woran erkennt man nun die unterschiedlichen Browser? Man muß sich auf die Suche nach Elementen machen die nur bei einem Browser auftauchen und bei anderen nicht. So könne man vorgehen: Netscape muß auf jeden Fall das Wort "Mozilla" und darf nicht das Wort "compatible" enthalten.
var isNavigator = ((agent.indexOf("mozilla") != -1) && (agent.indexOf("compatible") == -1));
Ein Internet Explorer könnte folgendermaße identifiziert werden:
var isExplorer = (agent.indexOf("msie") != -1);
Der Opera-Browser:
var isOpera = (agent.indexOf("opera") != -1);
(War es das? Nein. Neben den vielen anderen Browsern die es sonst noch gibt, kann man zu allem Überfluß im Opera einstellen wie bzw. als was er sich melden soll.)
Wie kann man nun die Versionsnummer ermitteln? Wie Sie am userAgent-Feld sehen hinkt der Explorer meist immer eine Versionsnummer des HTML-Interpreters Mozilla der offiziellen Versionsnummer hinterher. Daraus lassen sich also keine Rückschlüsse auf die Browserversion ziehen.
Hier kann man sich des appVersion-Feldes bedienen. Die Versionsnummer endet immer beim ersten Leerzeichen. Da ein String zurückgegeben wird, wird der Wert durch Multiplikation mit 1 in eine Zahl umgewandelt:
var ver = navigator.appVersion;
var version = ver.substring(0,ver.indexOf(" ")) * 1;
Das funktioniert recht gut, aber nur mit Netscape. Um die Versionsnummer vom Internet Explorer rauszufinden ist folgendes Konstrukt zu verwenden:
if (version < 4)
versionsnummer = 3;
if (version == 4 && navigator.userAgent.indexOf("msie 5") == -1)
versionsnummer = 4;
if (version == 4 && navigator.userAgent.indexOf("msie 5") != -1)
versionsnummer = 5;
Da besonders von Seiten Microsofts immer mit Überraschungen zu rechnen ist, muß der Code bei jeder neuen Version geprüft und ggf. angepaßt werden. Ausserdem kommen immer wieder neue Browser hinzu.
Nachdem der Browser nun leidlich erkannt ist, kann man den Nutzer auf eine Seite leiten, die sein Browser auch interpretieren kann. Wie geschieht das?
Eine Insatnz der Klasse window wird automatisch gebildet, wenn ein Browserfenster geöffnet wird. Diese Klasse beinhaltet als Eigenschaft eine weitere Klasse namens location, die wiederum eine Eigenschaft href besitzt. In dieser Variablen ist die URL der aufgerufenen Seite gespeichert. Der Aufruf ist also folgender:
var myURL = window.location.href
Umgekehrt ließe sich dieses Feld auch belegen, was folglich zu einem Wechsel der Seite führt:
if (isOpera)
window.location.href = "opera.htm"
Objekte können sich untereinander Botschaften oder "events" senden. Auf diese Botschaften kann mit sogenannten event-handlern reagiert werden. In der Regel mit einem Funktionsaufruf. Die event-handler werden in die geeigneten HTML-Tags als Attribute eingefügt und erhalten als Wert den entsprechenden JavaScript-Code. Zum Beispiel:
<A href="#" onClick="alert("Hallo")";
Hier eine Liste der event-handler, die JavaScript bereitstellt:
onBlur | Wenn ein Fenster oder Formularfeld den Fokus verliert |
onChange | Wenn der Wert eines Formularfeldes geändert wird |
onClick | Mausklick auf ein Element |
onFocus | Wenn ein Fenster oder Formularfeld den Fokus erhält |
onLoad | Beim Laden eines Dokumentes |
onMouseover | Wenn Die Maus über einen Link bewegt wird |
onMouseout | Wenn Die Maus aus einem Link heraus bewegt wird |
onUnload | Beim Verlassen eines Dokuments |
JS kennt, anders als objektorientierte Sprachen, keine Klassen, die als Muster für Objekte dienen. Das heißt, dass sich Objekte in JS jederzeit verändern (z.B. erweitern) lassen.
Ein sog. Objektliteral in JS hat einen Namen, der in geschweiften Klammern die Variablen und Methodendes Objekts einklammert. Variablen- und Funktionsnamen werden dabei durcu einen Doppelpunkt von ihren Werten getrennt:
var Person = {
name: 'Siegert',
vorname: 'Paul',
getName: function() { return this.name+" "+this.vorname;}
};
Setzen der Variablen:
Pesron.name = 'Brockdorff';
Lesen der Variablen:
var name = Pesron.name;
Aufrufen von Funktionen:
var name = Person.getName();
Konstruktoren (Funktionen innerhalb des Objekts mit gleichem Namen) müssen mit new aufgerufen werden und geben das Objekt selbst zurück:
var Person = {
name: '',
vorname: '',
person: function(initName, initVorname) {
this.name = initName;
this.vorname = init.vorname;
},
getName: function() {
return this.name+" "+this.vorname;
}
};
Der Aufruf muss wie folgt aussehen:
var einePerson = new Person('Paul','Siegert');
Vererbung
Wir können die Klasse Person mit extend erweitern. Wir legen ein Objekt für einen speziellen Typ von Person an, nämlich einen Dozenten. Der hat zwar wie alle Personen einen Vor- und einen Nachnamen, aber zusätzlich - anders als z.B. Studierende - ein Büro und eine Hausrufnummer.
var Dozent = Person.extend( {
buero:"",
tel:"",
dozent: function(initName, initVorname, initBuero, initTel) {
this._super(initName, initVorname);
this.buero = initBuero;
this.tel = initTel;
}
getAlleAngabe: function() {
return _super[name]+" "+_super[vorname]+" Büro:"+this.buero+" Tel.:"+this.tel;
}
});