JavaScript

Skriptsprache
Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 6. Februar 2005 um 17:29 Uhr durch Molily (Diskussion | Beiträge) (Links neugeordnet). Sie kann sich erheblich von der aktuellen Version unterscheiden.

JavaScript ist eine objektbasierte Skriptsprache, die von der Firma Netscape entwickelt wurde, um statischeHTML-Seiten dynamisch zu gestalten. Im Gegensatz zu serverseitigen Scriptsprachen wie zum Beispiel Perl oder PHP wird JavaScript auf dem Client ausgeführt. (Netscape nutzte JavaScript mit einem im Kern identischen Syntax allerdings auch serverseitig.) Mittels einer Schnittstelle zum Document Object Model (DOM) können Elemente der Webseite manipuliert werden, nachdem diese zum Client übertragen wurde.

Die Grundlagen von JavaScript wurden unter dem Namen ECMAScript unter ECMA-262 standardisiert. Die Syntax der Sprache ähnelt der der Programmiersprache Java und auch einige Schlüsselwörter beider Sprachen sind identisch. Semantisch jedoch unterscheiden sich beide Sprachen deutlich. Interessant ist die Tatsache, dass JavaScript im Gegensatz zu klassisch objektorientierten Sprachen keine Klassen einsetzt, sondern statt dessen Objekte als Prototypen einsetzt. Mittlerweile wurden auf dieser Basis zusätzlich normale Klassen implementiert, wohl in der Annahme, damit den Einstieg zu erleichtern.

JavaScript vereinheitlicht die aus anderen Sprachen bekannten Funktionen und Objekte zu einem einheitlichen Konzept. Die Sprache verfügt über integrierte Regular Expressions. Mit ECMAScript für XML (E4X, ECMA-357) wird auch XML als nativer Datentyp unterstützt.

Trotz des ähnlichen Namens ist JavaScript nicht mit der Programmiersprache Java zu verwechseln. Die Namensgleichheit entstand – ähnlich wie beim Java Enterprise System – aus Marketinggründen.

Rhino ist eine JavaScript-Implementierung, die als Open-Source-Projekt in Java geschrieben ist.

Geschichte

18. September 1995: Mit der Vorversion des Navigator 2.0 veröffentlicht Netscape einen Browser mit einer eingebetteten Skriptsprache. Sie heißt zu diesem Zeitpunkt entsprechend dem Produktportfolio LiveScript. Brendan Eich entwickelte die Sprache.

4. Dezember 1995: Netscape und Sun benennen die Sprache JavaScript, um mit dem Namen näher an Java heranzurücken.

5. März 1996: Mit dem Enterprise Server 2.0 von Netscape erscheint der erste Server, der JavaScript-Fähigkeiten besitzt. Die JavaScript-Variante unterscheidet sich zwangsläufig von der clientseitigen Variante.

29. April 1996: Mit der ersten Betaversion des Navigator 3.0 führt Netscape JavaScript 1.1 ein.

Mai 1996: Microsoft stellt mit der Betaversion des Internet Explorers 3 ihren ersten JavaScript-fähigen Browser vor. Die Skriptsprache heißt allerdings auch rechtlichen Gründen JScript und entspricht nur in etwa dem Stand vom Netscape Navigator 2. JScript schlägt einen eigenen Weg der Entwicklung ein, bleibt aber im wesentlich kompatibel zu JavaScript.

15. November 1996: Netscape und die ECMA bekunden eine standardisierte Form von JavaScript entwickeln zu wollen.

15. Oktober 1996: Mit der Ankündigung des Netscape Communicators (mit dem Navigator 4.0) kommt JavaScript 1.2.

4. Juni 1997: Der Netscape Communicator und damit der Navigator 4.0 mit JavaScript 1.2 erscheint.

Juni 1997: Die ECMA veröffentlicht ihren Standard ECMA-262: ECMAScript. Er wurde zusammen mit Netscape entwickelt.

1. Oktober 1997: Microsoft gibt den Internet Explorer 4 heraus, der den Sprachumfang von JavaScript 1.1 abdeckt. Darüber hinaus werden eigene Erweiterungen veröffentlicht, die zu Kompatibilitätsproblemen zwischen Navigator und Internet Explorer führen.

23. Februar 1998: Mozilla wird mit der Freigabe des Quelltexts vom Navigator auf den Weg gebracht.

April 1998: ECMAScript ist nun ISO-Norm: ISO/IEC 16262:1998 Information technology - ECMAScript language specification.

Juli 1998: Eine Betaversion des Netscape Communicators 4.5 wird veröffentlicht. JavaScript trägt nun die Version 1.3. Erstmals zu finden war diese JavaScript-Version schon in der Version 4.06 des Netscape Communicators.

Oktober 1998: Von Netscape wird JavaScript 1.4 vorgestellt. Diese Version ist vollständig kompatibel mit ECMA-262. Ein Browser mit der Unterstützung dieser Version erscheint jedoch nicht.

April 2000: Netscape gibt die Preview Release 1 vom Navigator 6 heraus, welcher auf dem in der Entwicklung befindlichen Browser Mozilla in der Version 0.6 beruht. Diese Version implementiert erstmals JavaScript 1.5.

5. Juni 2002: Mozilla 1.0 erscheint mit JavaScript 1.5.

Datenstrukturen und Objekte

JavaScript kennt mehrere eingebaute Objekte wie z.B. Object, Function, Array, String, Boolean, Number, Math, Date und RegExp. Diese werden von ECMAScript definiert. Die restlichen Objekte entstanden historisch vor allem durch die Netscape-Spezifikationen (window, document usw.) und setzten sich allmählich durch. Zahlreiche Unterobjekte von document wurden mittlerweile durch DOM HTML standardisiert (title, images, links, forms usw.).

Eigenschaften oder Methoden von Objekten werden über folgende Notation angesprochen:

objektname.eigenschaftsname
bzw.
objektname.methodenname()

Eine Übersicht der wichtigsten Eigenschaften und Methoden der einzelnen Objekte:

Objekte allgemein

Die Klasse "Object" definiert die gemeinsame Funktionalität aller JavaScript-Objekte.

neues Objekt erstellen:

var obj = new Object();

alternativ:

var obj = {};

In JavaScript ist es auch möglich, zur Laufzeit neue Eigenschaften zu einem Objekt hinzuzufügen oder zu entfernen. In diesem Beispiel wird "eigenschaftA" mit 1 belegt:

obj.eigenschaftA = 1;

Eine weitere Besonderheit der Javascript-Objekte ist die Fähigkeit, den Wert einer Eigenschaft direkt über den Namen zu ermitteln. In diesem Beispiel wird "1" ausgegeben:

window.alert( obj['eigenschaftA'] );

Außerdem ist es möglich, alle Eigenschaften eines Objektes in einer Schleife zu durchlaufen. In diesem Beispiel wird "obj.eigenschaftA=1" ausgegeben.

for (var i in obj) {
    window.alert('obj.' + i + '=' + obj[i]);
}

Array

arrayname = new Array(1,2,3,4,5,6)  // neues Array anlegen
arrayname = [1,2,3,4,5,6]           // neues Array anlegen (Alternative)
arrayname.length                    // Anzahl der Elemente zurückgeben
arrayname.concat(anderesArray)      // zwei Arrays verbinden
arrayname.join(Trennzeichen)        // Array in Zeichenkette umwandeln
arrayname.pop();                    // letztes Element aus Array löschen
arrayname.push(neuerWert)           // ein neues Element an das Ende des Array anhängen
arrayname.reverse()                 // Reihenfolge der Elemente umkehren

String

Ein String-Objekt kann in der Kurzschreibweise "Zeichenkette" oder 'Zeichenkette' notiert werden. Alternativ kann der String-Konstruktor verwendet werden: new String(10) gibt etwa 10 als String wieder.

teststring = "Hallo"              // neuen String anlegen
teststring = new String("Hallo")  // neuen String anlegen (Alternative)
teststring.length                     // Gibt die Länge des Strings wieder
teststring.toLowerCase()              // Gibt den String komplett kleingeschrieben wieder
teststring.toUpperCase()              // Gibt den String komplett großgeschrieben wieder
teststring.split(Trennzeichen)    // Wandelt den String durch ein Trennzeichens
                                      // in einen Array mit Teilstrings um 
teststring.indexOf(andererString) // Gibt die Position des ersten Vorkommens des
                                      // angegebenen Strings wieder. Wird dieser darin
                                      // gefunden, so gibt die Methode -1 zurück

Während die Kurzschreibweise "Hallo" ein Objekt des Typs String anlegt, entsteht bei new String("Hallo") ein Objekt des Typs Object. Dies ist in den meisten Fällen unwesentlich. In Falle der objektunabhängigen Funktion eval(), die einen String-Wert entgegennimmt und diesen als JavaScript-Ausdruck interpretiert, zeigt sich jedoch der feine Unterschied:

eval("25+25")             // gibt 50 wieder
eval(new String("25+25")) // gibt "25+25" wieder

Date

dateobjekt = new Date()   // neues Date-Objekt erzeugen

Math

Math.max(zahl1,zahl2)         // die größere der beiden Zahlen zurückgeben
Math.min(zahl1,zahl2)         // die kleiner der beiden Zahlen zurückgeben
Math.pow(Basiszahl, Exponent) // Ergebnis der Exponentialrechnung zurückgeben
Math.random()                         // Eine Zufallszahl zwischen 0 und 9 zurückgeben

Window Objekt

window.resizeTo(neueWeite, neueHoehe)            // Fenstergröße einstellen
window.moveTo(neue x-Position, neue y-Position)  // Fensterposition angeben
window.open("dateiname.htm", "Fenstername")      // neues Browserfenster öffnen

Screen Objekt

screen.width   // Bildschirmbreite zurückgeben
screen.height  // Bildschirmhöhe zurückgeben

Function Objekt

var f = function (zahl1, zahl2) {
  return zahl1 + zahl2;
};

alternativ:

f = new Function('zahl1', 'zahl2', 'return zahl1 + zahl2;');

Kontrollstrukturen

If ... else

if (Bedingung) {
    Anweisungen;
} else {
    Anweisungen;
}
while (Bedingung) {
    Anweisungen;
}

Do ... while

do {
    Anweisungen;
} while (Bedingung);
for ([Startausdruck]; [Bedingung]; [Inkrementier-Ausdruck]) {
    Anweisungen;
}

For ... in-Schleife

Mit dieser Anweisung werden alle Eigenschaften eines Objektes durchlaufen (oder auch alle Elemente eines Feldes).

for (variable in object) {
    Anweisungen;
}
switch (Ausdruck) {
    case marke1 :
        Anweisungen;
        break;
    case marke2 :
        Anweisungen;
        break;
    default :
        Anweisungen;
}

Funktionen

Eine Funktion ist ein Block mit einer Liste (evt. auch leer) von Parametern, dem ein Name zugewiesen wird. Eine Funktion kann einen Resultatwert zurückgeben.

function meineFunktion(param1, param2, param3) {
    Anweisungen;
    return Ausdruck;
}

Beispiel: Der ursprüngliche Algorithmus von Euklid zur Ermittlung des größten gemeinsamen Teilers: Es ist eine geometrische Lösung; die kleinere Strecke wird jeweils von der größeren abgezogen.

function gcd(a, b) {
    while (a != b) {
        if (a > b) {
            a = a - b;
        } else {
           b = b - a;
        }
    }
    return a;
}

Die Anzahl der Parameter beim Aufruf muss nicht zwingend mit der Anzahl der Parameter in der Funktionsdefinition übereinstimmen. Wenn beim Aufruf weniger Parameter angegeben werden, dann wird für die übrigen Parameter einfach der Wert undefined eingesetzt. Weiter kann innerhalb der Funktion auch über das arguments-Array auf die Parameter zugegriffen werden.

Konstruktor-Funktionen

Wird eine Javascript-Funktion genutzt, um mit new erstellte Objekte zu initialisieren, spricht man von einem Konstruktor. Innerhalb des Konstruktors kann das neue Objekt über die this-Variable angesprochen werden:

function meinObjekt () {
    this.zahl = 1;
}

Neue Instanz erstellen:

var obj = new meinObjekt();

Test der Eigenschaft "zahl". Es wird "1" ausgegeben.

window.alert(obj.zahl);

Wenn Sie eigene Objekte mit gemeinsamen Eigenschaften erstellen wollen, ist es oftmals besser, diese Eigenschaften nicht im Konstruktor, sondern über die Prototyp-Kette zu erstellen (siehe Vererbung). Auf diese Weise benötigen die Javascript-Objekte weniger Speicher, denn die Eigenschaften werden nicht für alle Objekte, sondern nur für den Prototyp abgelegt.

private Eigenschaften

Entgegen der vorherrschenden Meinung unterstützt Javascript private Eigenschaften, also Eigenschaften, die nur für das Objekt selbst sichtbar sind, nicht aber für andere Objekte. Im folgenden Beispiel wird die private Eigenschaft zahl1 definiert, die nur durch die Methoden getZahl1() und getNext() ausgelesen bzw. verändert werden kann.

function MyClass() {
    var zahl1 = 1;
    this.getZahl1 = function () { return zahl1; }
    this.getNext  = function () { return ++zahl1; }
}

neue Instanz der Klasse erstellen:

var obj = new MyClass;

zahl1 ist von außen nicht zugreifbar, daher wird "undefined" ausgegeben:

window.alert(obj.zahl1);

Es wird "1" ausgegeben:

window.alert(obj.getZahl1());

Es wird "2" ausgegeben

window.alert(obj.getNext());

Da Funktionen in JavaScript vollwertige Objekte sind, sind sie Funktionen höherer Ordnung und können auch als Parameter an andere Funktionen übergeben werden.

Die Lambda-Notation des Lambda-Kalküls wird so geschrieben:

function (x) { return x*x + 2*x + 10; }

Beispiel für Verwendung einer Funktion höherer Ordnung:

Array.prototype.fold =
function (value, functor) {
    var result = value;
    for (var i = 0; i < this.length; i++) {
        result = functor(result, this[i]);
    }
    return result;
}
var sum = [21,33,17,12].fold(0, function (a, b) { return a + b; })

Ebenso ist es möglich curried functions zu schreiben:

function add(a, b) {
    if (arguments.length < 1) return add;
    if (arguments.length < 2) return function(c) { return a + c; }
    else return a + b;
}

Vererbung (prototype-Eigenschaft)

Jedes Function-Objekt verfügt über eine prototype-Eigenschaft. Diese ist von besonderer Bedeutung, wenn die Funktion genutzt wird, um neue Objekte zu initialisieren (siehe Konstruktor). Die prototype-Eigenschaft definiert in diesem Falle gemeinsame Eigenschaften aller Objekte, die mit dem Konstruktor erstellt werden. Man spricht von Prototyp-basierter Vererbung. Auf diese Weise ermöglicht JavaScript mehrstufige Vererbung:

Konstruktor eines Prototyps erstellen:

function Kraftfahrzeug (Fabrikat) {
   this.Fabrikat = Fabrikat;
   this.Beispieleigenschaft = "Beispielwert";
}

Konstruktor des abgeleiteten Prototyps erstellen:

function PKW (Fabrikat) {
   this.constructor(Fabrikat);
   this.weitereEigenschaft = "Beispielwert";
}
PKW.prototype = new Kraftfahrzeug();

Eine neue Instanz des allgemeinen Prototyps dient als Muster des abgeleiteten Prototyps. Dadurch werden die Eigenschaften des allgemeinen Prototyps an den abgeleiteten Prototyp vererbt: Jedes PKW-Objekt ist gleichzeitig ein Kraftfahrzeug-Objekt. Über this.constructor kann im PKW-Konstruktor der Kraftfahrzeug-Konstruktor angesprochen werden. Dies wird im Beispiel dazu genutzt, die Parameter an letztgenannten weiterzugeben. So muss this.Fabrikat = Fabrikat; nur im Kraftfahrzeug-Konstruktor notiert sein.

Instanz des Prototyps PKW erstellen:

var Golf = new PKW("Volkswagen Golf");
var Ente = new PKW("Citroen 2CV");

Über die prototype-Eigenschaft der Konstruktorfunktion können einem Prototyp auch nachträglich Eigenschaften und Methoden hinzugefügt werden. Diese Änderungen wirken sich auf alle davon abgeleiteten Objekte aus:

PKW.prototype.Radanzahl = 4;
PKW.prototype.zeigeRadanzahl = function () {
   window.alert(this.Name + " hat " + this.Radanzahl + " Räder.");
};
Golf.zeigeRadanzahl(); // Volkswagen Golf hat 4 Räder.
Ente.zeigeRadanzahl(); // Citroen 2CV hat 4 Räder.

Eine nützliche Methode des Object-Prototyps ist hasOwnProperty(Eigenschaftsname). Sie gibt einen booleschen Wert, also true oder false zurück. Dadurch lässt sich ermitteln, ob eine bestimmte Eigenschaft durch dessen Konstruktor selbst oder durch seine Prototyp-Kette definiert wird. Im Beispiel ergibt Golf.hasOwnProperty("Radanzahl") false, ebenso wie Golf.hasOwnProperty("zeigeRadanzahl"). Beide Eigenschaften wurden nachträglich über PKW.prototype hinzugefügt. Golf.hasOwnProperty("Fabrikat") und Golf.hasOwnProperty("weitereEigenschaft") hingegen ergeben true, weil diese Eigenschaften durch die Konstruktoren Kraftfahrzeug und PKW belegt wurden.

Benutzerinteraktion

Meist erfolgt die Benutzerinteraktion über HTML-Formulare, auf deren Elemente man über das DOM zugreift. Es gibt jedoch auch einige einfache Arten, direkt mit dem Benutzer zu kommunizieren:

Alarm-Dialog

Gibt ein Fenster mit einer Textmeldung aus. Beispiel:

window.alert('Hallo Welt');

Bestätigungsdialog

Zeigt einen Dialog mit den Schaltflächen „OK“ und „Abbrechen“ an. Zurückgegeben wird ein boolescher Wert, je nachdem welche Schaltfläche der Benutzer ausgewählt hat.

var bestaetigt = confirm('Bitte best\xE4tigen');

Eingabeaufforderung

Es wird ein Dialog zur Informationseingabe angezeigt. Beispiel:

var eingabe = window.prompt("Hallo das ist die bearbeitung des Textes","");

andere Interaktionsmöglichkeiten

Die neueren Versionen von ECMAScript, wie sie im Internet Explorer 5 und Netscape Navigator 6 eingebaut sind, verfügen über eine von Java übernommene try ... catch Fehlerbehandlungsanweisung.

Die try ... catch ... finally Anweisung fängt Ausnahmen (exceptions), die aufgrund eines Fehlers oder einer throw-Anweisung auftreten, ab. Die Syntax ist wie folgt:

try {
    // Anweisungen, in denen Ausnahmen auftreten oder ausgelöst werden können
} catch (error) {
    // Anweisungsfolge, die im Ausnahmefall ausgeführt wird.
} finally {
    // Anweisungsfolge, die anschließend in jedem Fall ausgeführt wird.
}

Zu Beginn werden die Anweisungen im try-Block ausgeführt. Falls eine Ausnahme auftritt, wird der Kontrollfluss sofort zum catch-Block mit dem Ausnahmeobjekt als Parameter umgeleitet.

In Normalfall wird der Ausnahmeblock übersprungen. Nach der Ausführung des try-Blocks (auch teilweise) und gegebenenfalls des catch-Blocks werden in jedem Fall die Anweisungen im finally-Block ausgeführt.

try {
    Anweisungen
} catch (error) {
    // Fehlerbehandlung
} finally {
    Anweisungen
}

Der finally-Teil kann weggelassen werden

try {
    Anweisungen
} catch (error) {
    // Fehlerbehandlung
}

Siehe auch

Literatur