Java Script

Objekte

Objektorientierung

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.

  • Klassen beschreiben die Objekte abstrakt im Allgemeinen
  • Instanzen beschreiben individuelle Ausformungen einer Klasse
  • Objekte ist der allgemeine Oberbegriff

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.

  • Eigenschaften beschreiben in Variablen das, was das Objekt ausmacht.
  • Methoden beschreiben was man mit den Eigenschaften anstellen kann.

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

getDate() Ausgabe der Datumsvariablen
getDay() Ausgabe der Tagesvariablen
getMonth() Ausgabe der Monatsvariablen
getYear() Ausgabe der Jahresvariablen
getHours() Ausgabe der Stundenvariablen
getMinutes() Ausgabe der Minutenvariablen
getSeconds() Ausgabe der Sekundenvariablen
getMilliseconds() Ausgabe der Millisekundenvariablen
getTime() Ausgabe der Millisekunden seit dem 1.1.1970
setDate() Setzen der Datumsvariable
setHours() Setzen der Studnenvariable
setMinutes() Setzen der Minutenvariable
setMonth() Setzen der Monatsvariable
setSeconds() Setzen der Sekundenvariable
setTime() Setzen der Zeitvariable (Millisekunden seit dem 1.1.1970)
setYear() Setzen der Jahresvariable
toGMTString() liefert Datum und Uhrzeit als Greenwich Mean Time

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:

  • 1989 => 89
  • 2001 => 101
  • 1800 => -100

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:

  • Man kann abfragen ob ein Objekt von einem Browser unterstützt wird, und dann entsprechend darauf reagieren.
  • Bestimmte Funktionen höherer JavaScript Versionen lassen sich auch mit JavaScript 1.0 "von Hand" nachbilden.
  • Verwenden verschiedener Werte des language-Attributs im Script-Tag.
  • Browsererkennung und Umleitung auf eine entsprechende Seite bzw. Code.

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"

Event-Handler

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
Objektorientierung

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;
}
});