Informatik 2 Einführung in JavaScript Prof. Dr.-Ing. Holger Vogelsang [email protected] Inhaltsverzeichnis Prinzipien (3) Einstieg (11) Funktionen (38) Objekte und Vererbung (46) Module (63) Private Daten (69) DOM-Zugriffe (72) Ende (83) Holger Vogelsang Informatik 2 - Einführung in JavaScript 2 Prinzipien Übersicht Grafische Oberflächen Übersicht Datenstrukturen ADTs Typinfo., I/O Annotationen JavaScript Prinzipien Holger Vogelsang Layouts Ereignisse Datenstrukturen in Java Laufzeittypinfo. Einstieg Widgets Grafikoperationen Elementare Datenstrukturen Grafikwidgets Effekte, Animationen Iteratoren Hashtabellen Bäume Module Private Daten DOMZugriffe Offene Punkte Graphen Ein-, Ausgabe Funktionen Objekte und Vererbung Informatik 2 - Einführung in JavaScript 3 Prinzipien Motivation Eigenschaften von JavaScript Laufzeitumgebungen Holger Vogelsang Informatik 2 - Einführung in JavaScript 4 Prinzipien Skriptsprachen Was sind die Merkmale einer Skriptsprache (nicht genau definiert)? Häufig über einen Interpreter ausgeführt, keine Compilierung erforderlich Implizit deklarierte Variablen, schwache Typisierung: Variablentypen werden zur Laufzeit erkannt Ducktyping Dynamische Programmänderung: Hinzufügen von Klassen, Methoden und Attributen zur Laufzeit Automatische Speicherverwaltung wie in Java und C# Oft weniger „geschwätzig“ höherer Abstraktionsgrad, domänenspezifische Sprachen Holger Vogelsang Informatik 2 - Einführung in JavaScript 5 Prinzipien Skriptsprachen Vorteile von Skript-Sprachen: schnelle Entwicklungen (Rapid Prototyping) kein Compiler-Schritt erforderlich Austausch von Code zur Laufzeit Domain-spezifische Sprachen Nachteile von Skript-Sprachen: − Typfehler erst zur Laufzeit sichtbar viel mehr testen − schlechte IDE-Unterstützung (Typen fehlen), Vorschläge wie hier bei Java sind nicht so genau möglich: − geringere Ausführungs-Geschwindigkeit − weniger „Best Practices“ vorhanden Holger Vogelsang Informatik 2 - Einführung in JavaScript 6 Prinzipien Geschichte der Sprache 1995: LiveScript im Browser Netscape Navigator 2.0 1996: Nach Umbenennung JavaScript 1.1 im Netscape Navigator 3 und im Internet Explorer 3.0. 1998: JavaScript 1.3 wird im Standard ECMA-262 festgehalten. … 2008: JavaScript 1.8.5 wird im Standard ECMAScript 5 Compliance festgehalten darauf basiert die Einführung in der Vorlesung Die Syntax von Java ähnelt der von JavaScript, die Semantik ist teilweise aber deutlich anders. Holger Vogelsang Informatik 2 - Einführung in JavaScript 7 Prinzipien Eigenschaften Laufzeitumgebung auf dem Client: Z.B. im Browser zur Manipulation von Web-Seiten. URL-Aufruf Antwort Browser JavaScriptFunktionen Web Server lesen Aufruf HTML-Seiten, Bilder, JavaScript-Dateien, CSS-Dateien … (Dateisystem) JavaScript läuft in einer „Sandbox“ und kann nicht auf das Betriebssystem des Anwenders zugreifen. Auf diese Anwendung beschränkt sich die Vorlesung im Wesentlichen. Holger Vogelsang Informatik 2 - Einführung in JavaScript 8 Prinzipien Eigenschaften Laufzeitumgebung auf dem Server: Als Server-Anwendung, Auslieferung von Web-Seiten und anderen Informationen. Browser URL-Aufruf Antwort Web Server URL-Aufruf (+ Parameter) Antwort lesen Schnittstelle Aufruf JavaScriptProgramme HTML-Seiten, Bilder, JavaScript-Dateien, CSS-Dateien … (Dateisystem) Diese Anwendung wird in der Vorlesung nicht behandelt. Holger Vogelsang Informatik 2 - Einführung in JavaScript 9 Prinzipien Eigenschaften Laufzeitumgebung ist eine JVM zur Erweiterung oder Konfigurierung von Java-Programmen. K1 K3 K2 Zugriff Interpreter Ereignis Ausführung JavaScript Java-Objekte GUI Diese Anwendung wird in der Vorlesung nicht behandelt kleines Beispiel in der Vorlesung „Benutzungsoberflächen“. Holger Vogelsang Informatik 2 - Einführung in JavaScript 10 Einstieg Übersicht Grafische Oberflächen Übersicht Datenstrukturen ADTs Typinfo., I/O Annotationen JavaScript Prinzipien Holger Vogelsang Layouts Ereignisse Datenstrukturen in Java Laufzeittypinfo. Einstieg Widgets Grafikoperationen Elementare Datenstrukturen Grafikwidgets Effekte, Animationen Iteratoren Hashtabellen Bäume Module Private Daten DOMZugriffe Offene Punkte Graphen Ein-, Ausgabe Funktionen Objekte und Vererbung Informatik 2 - Einführung in JavaScript 11 Einstieg Das erste JavaScript-Programm Als Laufzeitumgebung für die folgenden kleinen Beispiele eignet sich die Konsole des Chrome- oder des Firefox-Browsers ganz gut: Chrome: Tools JavaScript-Konsole Firefox: Entwickler-Werkzeuge JavaScript-Umgebung zur Eingabe und Entwickler Browser-Konsole zur Ausgabe (vorher eventuell noch Firebug installieren) Eingabe in die Konsole (entspricht ungefähr System.out.println in Java): console.log('Hello World'); Ein- und Ausgabe (Chrome): Holger Vogelsang Informatik 2 - Einführung in JavaScript 12 Einstieg Das erste JavaScript-Programm Ein- und Ausgabe (Firefox): Es sind einfache und doppelte Anführungszeichen erlaubt. console ist ein im Browser vorhandenes JavaScript-Objekt. Holger Vogelsang Informatik 2 - Einführung in JavaScript 13 Einstieg Das erste JavaScript-Programm Ab jetzt: Beispiele in der WebStorm-IDE: Node.js von http://nodejs.org/#download herunterladen und installieren WebStorm von http://www.jetbrains.com/webstorm/download/ herunterladen (Lizenz im Ilias), installieren WebStorm starten und in File Settings JavaScript Browser den Pfad auf node.exe eintragen (falls nicht automatisch gefunden, je nach Betriebssystem hat die Datei natürlich eine andere oder keine Endung). Neues, leeres Projekt anlegen Zum Projekt eine JavaScript-Datei Console.js (Name ist nicht wichtig) hinzufügen und console.log('Hello World'); eintragen. Holger Vogelsang Informatik 2 - Einführung in JavaScript 14 Einstieg Das erste JavaScript-Programm Ergebnis: Holger Vogelsang Informatik 2 - Einführung in JavaScript 15 Einstieg Das erste JavaScipt-Programm Einbettung von JavaScript in eine HTML-Datei (EmbeddedJavaScript.html): <!DOCTYPE html> <html> <head lang="de"> <meta charset="UTF-8"> <title>Hello World</title> <script> alert('Hello World'); </script> </head> <body> <h1>Titelzeile</h1> </body> </html> alert() ist eine vordefinierte Funktion in Browsern, die einen kleinen Dialog öffnet. Der Dialog wird hier beim Laden der Seite und vor dem Anzeigen des Inhalts eingeblendet. Holger Vogelsang Informatik 2 - Einführung in JavaScript 16 Einstieg Das erste JavaScipt-Programm Laden einer externen JavaScript-Datei (ExternalJavaScript.html): function showMessage(message) { <!DOCTYPE html> alert(message); <html> } <head lang="de"> <meta charset="UTF-8"> <title>Hello World</title> <script type="text/javascript" src="./js/External.js"></script> Laden </head> der Datei <body> <h1>Hello World</h1> <script>showMessage('Hello World')</script> Aufruf </body> der Funktion </html> Das erste script-Tag erhält mit dem src-Attribut den Namen einer JavaScript-Datei. Das zweite script-Tag enthält den Aufruf der geladenen Funktion. Die Funktion wird aufgerufen, wenn der Teil der HTML-Seite geladen ist. Holger Vogelsang Informatik 2 - Einführung in JavaScript 17 Einstieg Datentypen Es gibt in JavaScript nur sehr wenigen Datentypen: object: Objekte, entsprechen ungefähr Maps in Java, zu denen Methoden und beliebige Attribute hinzugefügt werden können. Auch Arrays sind Objekte. string: Zeichenketten, entsprechen ungefähr der String-Klasse in Java. number: Zahlen boolean: Wahrheitswerte Eine Variable wird ohne Typangabe angelegt: var year = 2000; Typ einer Variablen zur Laufzeit auslesen, Operator typeof: var year = 2000; console.log(typeof year); // Ausgabe: number year = 'Vogelsang'; console.log(typeof year); // Ausgabe: string Das Schlüsselwort var kann weggelassen werden, sollte aber nicht: Ohne die Angabe wird eine globale Variable erzeugt. Tipp: Jede JavaScript-Datei mit 'use strict'; einleiten gewisse alte Eigenschaften der Sprache (z.B. Verzicht auf var) erzeugt Laufzeitfehler. Holger Vogelsang Informatik 2 - Einführung in JavaScript 18 Einstieg Datentypen: object Objekte sind eigentlich nur Maps: Attribute bestehen aus Schlüssel (Attributnamen) und Wert (Wert des Attributs) Attributwerte können von einem beliebigen Typ sein auch Funktionen! Attribute lassen sich zur Laufzeit hinzufügen und mit delete entfernen. Sie würden in Java einer Map<String, Object> entsprechen. Erzeugen eines leeren Objektes (Konstruktoren usw. kommen später): var obj1 = {}; obj1 ist eine Variable mit einer Referenz auf das Objekt. Erzeugen eines Objektes mit Attributen: var obj2 = { lastname: 'Vogelsang', firstname: 'Holger' }; Zugriff auf die Attribute mit „.“ oder „[]“ (Angabe des Schlüssels = Attributname, Rückgabe der Wert): console.log(obj2.lastname); console.log(obj2['lastname']); Holger Vogelsang Informatik 2 - Einführung in JavaScript 19 Einstieg Datentypen: object Attribute können jederzeit überschrieben werden: obj2.lastname = 'Gmeiner'; Es dürfen neue Attribute hinzugefügt werden: obj2.age = 42; obj2.role = function() { return 'Dozent'; }; Da Funktionen Objekte sind, dürfen sie einem Attribut als Wert zugewiesen werden. Auf solche Funktionen wird später genauer eingegangen (und wie man das besser machen kann). Entfernen eines Attributs aus einem Objekt: delete obj2.age; console.log(obj2.age); // Ausgabe: undefined Typ eines Objekts: console.log(typeof obj2); // Ausgabe: object Holger Vogelsang Informatik 2 - Einführung in JavaScript 20 Einstieg Datentypen: object (Array) Erzeugen eines Arrays: var values = [1, 2, 3, 4]; Typ eines Arrays: console.log(typeof values); // Ausgabe: object Zugriff auf Array-Elemente: console.log(values[0]); // Ausgabe: 1 console.log(values); // Ausgabe: [ 1, 2, 3, 4 ] Ändern der Array-Elemente, es müssen nicht alle Daten im Array denselben Typ haben: values[ 2 ] = 'Name'; console.log(values); // Ausgabe: [ 1, 2, 'Name', 4 ] Arrays sind im Gegensatz zu Java in ihrer Größe veränderlich. Anhängen neuer Werte an das Ende des Arrays mit push: values.push(42, 66); console.log(values); // Ausgabe [ 1, 2, 'Name', 4, 42, 66 ] Holger Vogelsang Informatik 2 - Einführung in JavaScript 21 Einstieg Datentypen: object (Array) Entfernen von Werten aus dem Array mit splice: values.splice(1, 2); // an Position 1 werden 2 Elemente entfernt console.log(values); // Ausgabe [ 1, 4, 42, 66 ] Mit splice lassen sich auch Werte einfügen (siehe JavaScript-Referenz). Länge eines Arrays: var values = [1, 2, 3, 4]; console.log(values.length); // Ausgabe: 4 Die Länge kann vergrößert oder verkleinert werden: values.length = 6; console.log(values); // Ausgabe: [ 1, 2, 3, 4, , console.log(values[ 5 ]); // Ausgabe: undefined values.length = 3; console.log(values); // Ausgabe: [ 1, 2, 3 ] ] Es darf auch über die Array-Grenzen hinaus geschrieben werden. Dabei wird das Array automatisch vergrößert: values = [1, 2, 3, 4]; values[ 8 ] = 8; console.log(values); // Ausgabe: [ 1, 2, 3, 4, , , , , 8 ] Holger Vogelsang Informatik 2 - Einführung in JavaScript 22 Einstieg Datentypen: object (Array) Es gibt weitere Methoden, z.B. shift (verschiebt alle Elemente um eines nach links): values = [1, 2, 3, 4]; values.shift(); console.log(values); // Ausgabe (die 1 ist jetzt weg): [ 2, 3, 4 ] Die JavaScript-Referenz sowie die Code-Vervollständig in z.B. WebStorm zeigen viele weitere Methoden auf Arrays. Holger Vogelsang Informatik 2 - Einführung in JavaScript 23 Einstieg Datentypen: object (string) Strings sind denen aus Java ähnlich. Einfache Anführungszeichen (oft bevorzugte Variante): var name = 'Vogelsang'; Doppelte Anführungszeichen: var name = "Vogelsang"; Der Typ eines Strings ist string: console.log(typeof name); // Ausgabe: string Jedes Zeichen eines Strings ist wiederum ein String: var first = name[ 0 ]; console.log(typeof first); // Ausgabe: string Es gibt also kein einzelnes char wie in Java. Strings lassen sich mit += und + verbinden kann langsam sein, weil viele Zwischenobjekte erzeugt werden. Besser, wenn die Strings im Array vorliegen: var strings = ['a', 'b', 'c', 'd' ]; var result = strings.join('-'); // Alle verbinden, Trennzeichen ist '-' console.log(result); // Ausgabe: a-b-c-d Holger Vogelsang Informatik 2 - Einführung in JavaScript 24 Einstieg Datentypen: object (string) Die JavaScript-Referenz sowie die Code-Vervollständig in z.B. WebStorm zeigen viele weitere Methoden auf Strings. Holger Vogelsang Informatik 2 - Einführung in JavaScript 25 Einstieg Datentypen: object (number) Es gibt in JavaScript mit number nur einen Zahlentyp. Er entspricht im Wesentlichen double in Java. Beispiele: var age = 22; console.log(age); console.log(typeof age); // Ausgabe: 22 // Ausgabe: number var price = 42.33; console.log(price); console.log(typeof price); // Ausgabe: 42.33 // Ausgabe: number console.log(age * price); // Ausgabe: 931.26 Zwischen string und number kann manuell umgewandelt werden: age = parseInt("42.33"); console.log(age); console.log(typeof age); // Ausgabe: 42 // Ausgabe: number price = parseFloat("42.33"); console.log(price); // Ausgabe: 42.33 console.log(typeof price); // Ausgabe: number Holger Vogelsang Informatik 2 - Einführung in JavaScript 26 Einstieg Datentypen: object (number) Eine Fließkommazahl kann gerundet werden, dabei darf die Anzahl der Nachkommastellen angegeben werden: price = 22.66; price = price.toFixed(); console.log(price); // Rundung in ganze Zahl // Ausgabe: 23 price = 22.66; price = price.toFixed(1); console.log(price); // Rundung auf eine Nachkommastelle // Ausgabe: 22.7 Zahlen sind also immer Objekte! Was passiert beim Rechnen, wenn Fehler auftreten? Es gab bei der Einführung von JavaScript noch keine Exceptions. Es werden Fehlerinformationen in der Variablen gespeichert. Holger Vogelsang Informatik 2 - Einführung in JavaScript 27 Einstieg Datentypen: object (number) Beispiele: var result = price / 0; console.log(result); console.log(typeof result); result *= 10; console.log(result); result = 0 / 0; console.log(result); console.log(typeof result); result /= (0 / 0); console.log(result); // Ausgabe: Infinity // Ausgabe: number // Ausgabe: Infinity // Ausgabe: NaN (steht für Not a Number) // Ausgabe: number // Ausgabe: NaN Weitere Mathe-Operationen sind über das Math-Objekt verfügbar. Holger Vogelsang Informatik 2 - Einführung in JavaScript 28 Einstieg Datentypen: object (boolean) Für Wahrheitswerte gibt es den Datentyp boolean: var dead = false; console.log(dead); // Ausgabe: false console.log(typeof dead); // Ausgabe: boolean Holger Vogelsang Informatik 2 - Einführung in JavaScript 29 Einstieg Variable: Typen Erinnerung: Variablen werden keine festen Datentypen zugewiesen. Variablen haben zur Laufzeit Typen, die sich ändern können. Wie kann trotzdem mit Werkzeugunterstützung halbwegs sicher programmiert werden? Lösung: Typhinweis im Kommentar, der von der IDE wie WebStorm, ausgewertet wird. Beispiel in WebStorm: Warnung Einblendung unter dem Mauszeiger: Aber das ist erlaubt und funktioniert! Holger Vogelsang Informatik 2 - Einführung in JavaScript 30 Einstieg Variable: Blöcke In Java lebt eine Variable nur innerhalb des zugehörigen Blocks („zwischen den geschweiften Klammern“). In JavaScript begrenzen nur Funktionen die Lebensdauern von Variablen. Beispiel: for (var x = 0; x < 10; x++) { console.log(x); } console.log("Nach der Schleife: " + x); x ist nach Beendigung der Schleife noch sichtbar und hat den Wert 10. Beispiel zu Funktionen: function calc() { var x = 0; console.log(x); } x ist außerhalb der Funktion nicht mehr sichtbar. Holger Vogelsang Informatik 2 - Einführung in JavaScript 31 Einstieg Variable: Vergleiche Es gibt zwei Vergleichsoperatoren: ==, !=: Test auf Gleichheit bzw. Ungleichheit, notfalls mit Hilfe von Konvertierungen („equals operator“) ===, !==: Gleichheit bzw. Ungleichheit ohne Konvertierung („strict equals operator“), entspricht eher dem == bzw. != in Java, ist in JavaScript bevorzugt zu verwenden. Objekte und Arrays werden über ihre Referenzen, nicht den Inhalt, vergleichen. Beispiele: 1 == true true 1 === true false 1 == "1" true var obj1 = {}; false var obj2 = {}; obj1 == obj2 Holger Vogelsang 1 === "1" false var obj1 = {}; false var obj2 = {}; obj1 === obj2; Informatik 2 - Einführung in JavaScript 32 Einstieg Variable: Undefinierter Inhalt In Java stellt der Compiler sicher, dass es keine Zugriffe auf nicht initialisierte Variable gibt und dass alle Variablen, auf die zugegriffen wird, auch existieren. In JavaScript gibt es keinen Compiler: Variable können beim Zugriff uninitialisiert sein. Beispiel: var name; console.log(name); // Ausgabe: undefined console.log(typeof name); // Ausgabe: undefined Beispiel für den Test auf Initialisierung: var name1; console.log(typeof name1 === 'undefined'); // Ausgabe: true Wie in Java dient null der gezielten Initialisierung mit „nichts“. Beispiel: var name2 = null; console.log(typeof name2 === 'undefined'); // Ausgabe: false console.log(typeof name2); // Ausgabe: object (null ist vom Typ object) Zugriff auf eine nicht vorhandene Variable: console.log(name3); // Programmabbruch Holger Vogelsang Informatik 2 - Einführung in JavaScript 33 Einstieg Variable: Undefinierter Inhalt Beispiel zum Zugriff auf eine nicht initialisierte bzw. nicht vorhandene Eigenschaft eines Objektes: var object = { attr1: undefined }; console.log(object.attr1); // Ausgabe: undefined console.log(object.attr2); // Ausgabe: undefined Tipp: Initialisieren Sie alle Variablen und Attribute während ihrer Deklaration. Es gibt keinen Compiler, der die Initialisierung sicherstellt. Holger Vogelsang Informatik 2 - Einführung in JavaScript 34 Einstieg Kontrollstrukturen Vergleich mit Java Anweisung Java JavaScript if Bedingung muss ein Boole‘scher Wert sein Bedingung ist true für alles außer false, undefined, null, 0, NaN, "" switch erlaubte Typen: ganzzahlige Werte, String, Aufzählungen wie in Java, Wert wird mit === vergleichen ?: wie in Java while, do … while, break, continue wie in Java for ähnlich zu Java, Laufvariable vom „Typ“ var ist auch außerhalb der Schleife sichtbar Holger Vogelsang Informatik 2 - Einführung in JavaScript 35 Einstieg Kontrollstrukturen Es gibt noch eine besondere Form der for-Schleife: for … in Die Schleife iteriert über alle Properties eines Arrays oder Objektes. Beispiel: // Objekt mit zwei Attributen var object = { attr1: 1, attr2: 2 }; // Array mit vier Werten var values = [1, 2, 3, 4]; // Durchlaufen aller Properties (Attribute) des Objektes for (var p1 in object) { console.log('Attribut ' + p1 + ' = ' + object[p1]); } // Durchlaufen aller Properties (Indizes) des Arrays for (var p2 in values) { console.log('Index ' + p2 + ' = ' + values[p2]); } Holger Vogelsang Informatik 2 - Einführung in JavaScript 36 Einstieg Ausnahmen Ausnahmen sehen denen in Java recht ähnlich. Ausnahme: Es gibt keine Klassen! Eine Ausnahme ist ein Objekt. Beispiel: try { throw 'Eingabefehler'; // Oder besser: throw new Error('Eingabefehler'); } catch (error) { console.log('Fehler: ' + error); } finally { console.log('Wie in Java immer aufgerufen'); } Holger Vogelsang Informatik 2 - Einführung in JavaScript 37 Funktionen Übersicht Grafische Oberflächen Übersicht Datenstrukturen ADTs Typinfo., I/O Annotationen JavaScript Prinzipien Holger Vogelsang Layouts Ereignisse Datenstrukturen in Java Laufzeittypinfo. Einstieg Widgets Grafikoperationen Elementare Datenstrukturen Grafikwidgets Effekte, Animationen Iteratoren Hashtabellen Bäume Module Private Daten DOMZugriffe Offene Punkte Graphen Ein-, Ausgabe Funktionen Objekte und Vererbung Informatik 2 - Einführung in JavaScript 38 Funktionen Einführung Auch Funktionen sind Objekte, die Variablen zugewiesen werden können. Sie „können“ wesentlich mehr als Methoden in Java oder Funktionen in C/C++. Eine Funktion kann einen eigenen Namen und Übergabeparameternamen besitzen. Beispiele ohne Parameter: // Definition der Funktion print. function print() { console.log('Aufgerufen 1'); } // Aufruf der Funktion print: print(); // Ausgabe: Aufgerufen 1 // Definition der Variablen printer, die eine anonyme Funktion aufnimmt. var printer = function() { console.log('Aufgerufen 2'); }; // Aufruf der anonymen Funktion mit Hilfe der Variablen printer(); // Ausgabe: Aufgerufen 2 Holger Vogelsang Informatik 2 - Einführung in JavaScript 39 Funktionen Einführung Da eine Funktion ein Objekt ist, lassen sich auf Funktions-Objekten Methoden aufrufen. Beispiel: // Definition der Funktion print. var printer = function() { console.log('Aufgerufen 2'); } // Direkter Aufruf der Funktion: printer(); // Aufruf über die call-Methode des Funktions-Objektes: printer.call(); Holger Vogelsang Informatik 2 - Einführung in JavaScript 40 Funktionen Einführung Parameter und Rückgabewerte einer Funktion sind im Quellcode „typlos“: function minSqr(x, y) { return x < y ? x * x : y * y; } console.log(minSqr(2,3)); Da ein Aufrufer die Typen nicht erkennen kann, sollten sie immer im JsDoc-Kommentar in geschweiften Klammern angegeben werden. So können IDEs wie WebStorm sie erkennen und Prüfungen vornehmen. /** * Berechnet den Quadratwert des Minimums zweier Zahlen. * @param {number} x Erste zu vergleichende Zahl. * @param {number} y Zweite zu vergleichende Zahl. * @returns {number} Das Minimum beider Argumente. */ function minSqr(x, y) { return x < y ? x * x : y * y; } console.log(minSqr(2,3)); console.log(minSqr('aa', 'bb')); Warnung von WebStorm Optionale Parameter und variable Parameteranzahlen werden hier nicht betrachtet. Holger Vogelsang Informatik 2 - Einführung in JavaScript 41 Funktionen Höherer Ordnung Da Funktionen Objekte sind, können sie als Parameter an andere Funktionen übergeben werden. Beispiel: Durchlaufen eines Arrays mit einer forEach-Schleife: var values = [1, 2, 3, 4, 5]; values.forEach(function (value) { console.log(value); }); forEach erwartet eine Funktion als Parameter, vielleicht so besser erkennbar: var logger = function(value) { console.log(value); }; values.forEach(logger); Bereits von der Stream-API in Java bekannt! Holger Vogelsang Informatik 2 - Einführung in JavaScript 42 Funktionen Höherer Ordnung Wozu das Ganze? Es geht doch auch prozedural mit Index-Zugriff. Vorteil: Längere „Verkettung“ von Aufrufen wie bei der Stream-API in Java. Beispiel zur Verkettung, Ausgabe nur der geraden Werte des Arrays values: values.filter(function(value) { return value % 2 == 0; }).forEach(function(value) { console.log(value); }); Funktionen: Die Funktion im filter-Argument liefert true, wenn der Wert im Ergebnis vorhanden sein soll. Die Funktion im forEach-Argument wird für jeden Wert, den der Filter durchgelassen hat, aufgerufen. Holger Vogelsang Informatik 2 - Einführung in JavaScript 43 Funktionen Höherer Ordnung Mächtiges Konzept der map- und reduce-Aufrufe bei Arrays: map bildet jeden Wert auf einen neuen ab. reduce erzeugt aus allen Werten des Arrays ein Ergebnis. Beispiel zur Summierung der Quadratzahlen aller Arraywerte aus values: var result = values.map(function(value) { return value * value; }).reduce(function(tempReducedValue, value) { return tempReducedValue + value; }); console.log('Summe der Quadratzahlen: ' + result); Funktionen: Die Funktion im map-Argument erhält als Argument in jedem Aufruf einen Wert des Arrays und liefert als Ergebnis den neuen Wert zurück. Die Funktion im reduce-Argument erhält als Werte das bisherige Zwischenergebnis (tempReducedValue) sowie das von map berechnete neue Argument (value). reduce liefert das neue Zwischenergebnis zurück. Holger Vogelsang Informatik 2 - Einführung in JavaScript 44 Funktionen Hoisting JavaScript sortiert die Deklarationen der Variablen in einer Funktion um, so dass immer alle Deklarationen am Anfang stehen („Hoisting“: an den Anfang der Funktion gehoben). Die Initialisierungen erfolgen aber erst dort, wo sie auch im Quelltext stehen. Beispiel: function hoistingDemo() { console.log(value); // Ausgabe: undefined var value = 10; console.log(value); // Ausgabe: 10 } entspricht hoistingDemo(); function hoistingDemo() { var value; console.log(value); value = 10; console.log(value); } hoistingDemo(); Der erste console.log-Aufruf links im Beispiel erzeugt keinen Fehler, da value schon bekannt, aber nicht initialisiert ist. Tipp: Alle Variablen immer am Anfang einer Funktion deklarieren. Holger Vogelsang Informatik 2 - Einführung in JavaScript 45 Objekte und Vererbung Übersicht Grafische Oberflächen Übersicht Datenstrukturen ADTs Typinfo., I/O Annotationen JavaScript Prinzipien Holger Vogelsang Layouts Ereignisse Datenstrukturen in Java Laufzeittypinfo. Einstieg Widgets Grafikoperationen Elementare Datenstrukturen Grafikwidgets Effekte, Animationen Iteratoren Hashtabellen Bäume Module Private Daten DOMZugriffe Offene Punkte Graphen Ein-, Ausgabe Funktionen Objekte und Vererbung Informatik 2 - Einführung in JavaScript 46 Objekte und Vererbung Einführung Bisher wurden in der Vorlesung eigene Objekte direkt als Hash-Tabelle angelegt. Nachteile: Es fehlte der Konstruktoraufruf. Es können nicht mehrere Objekte eines Typs erzeugt werden. Methoden werden (wie Attribute) einzelnen Objekten zugeordnet. Besseres Vorgehen: Erzeugen von Objekten mit Hilfe von Konstruktorfunktionen. Beispiel: /** * Erzeugt einen Kunden. * @param {string} name * @param {number} age * @param {number} no * @constructor */ function Customer(name, age, no) { this.name = name; this.age = age; this.no = no; } var c1 = new Customer('Test', 42, -1); Holger Vogelsang Informatik 2 - Einführung in JavaScript 47 Objekte und Vererbung Einführung Was passiert in dem Beispiel? Es wird eine „normale“ Funktion definiert. Es wird mit new ein Objekt erzeugt und dabei die Funktion aufgerufen. Die Funktion initialisiert das Objekt. Jetzt können beliebig viele Objekte mit den in der Konstruktorfunktion angegebenen Attributen angelegt werden. Wo sind die Methoden? Sie sollten nicht direkt in Attributen des Objekts gespeichert werden: Sie wären als Attribut in jedem erzeugten Objekt vorhanden. Vererbung (kommt gleich) würde nicht gut funktionieren. Jedes Objekt besitzt ein Attribut prototype. Es kann mit Hilfe der statischen Methoden getPrototypeOf des Typs Object ausgelesen werden. Beispiel: console.log(Object.getPrototypeOf(c1)); An diesem Attribut werden die Methoden gespeichert. Holger Vogelsang Informatik 2 - Einführung in JavaScript 48 Objekte und Vererbung Einführung Gemeinsamer Prototyp aller durch eine Konstruktorfunktion erzeugten Objekte. Beispiel: var c1 = new Customer('Test1', 42, -1); var c2 = new Customer('Test2', 44, -1); c1 c2 prototype Zuordnung von „Methoden“ zu dem Customer-Typ, hier drei Getter: Customer.prototype.getNo = function() { return this.no; }; Customer.prototype.getAge = function() { return this.age; }; Customer.prototype.getName = function() { return this.name; }; Holger Vogelsang Informatik 2 - Einführung in JavaScript 49 Objekte und Vererbung Einführung Aufruf der „Methoden“: console.log(c1.getAge()); console.log(c1.getName()); console.log(c1.getNo()); Zusammenfassung: Alle Attribute in der Konstruktorfunktion initialisieren. Nicht vorhandene Attribute werden automatisch angelegt. „Methoden“ außerhalb der Konstruktorfunktion dem Prototypen des Typs zuweisen. Holger Vogelsang Informatik 2 - Einführung in JavaScript 50 Objekte und Vererbung Einführung Vollständiges Beispiel mit den Getter-Methoden (Getter sind hier eigentlich sinnlos, weil die Attribute ohnehin öffentlich les- und schreibbar sind): /** * Erzeugt einen Kunden. * @param {string} name * @param {number} age * @param {number} no * @constructor */ function Customer(name, age, no) { this.name = name; this.age = age; this.no = no; } /** * Gibt die Kundennummer zurück. * @returns {number} Kundennummer. */ Customer.prototype.getNo = function() { return this.no; }; Holger Vogelsang @constructor ist ein Hinweis an die IDE Zuweisung außerhalb der Funktion, da ansonsten bei jedem neuen Objekt erneut zugewiesen wird. Informatik 2 - Einführung in JavaScript 51 Objekte und Vererbung Einführung Die beiden weiteren Methoden: /** * Gibt das Alter des Kunden zurück. * @returns {number} Alter des Kunden. */ Customer.prototype.getAge = function() { return this.age; }; /** * Gibt den Namen des Kunden zurück. * @returns {string} Name des Kunden. */ Customer.prototype.getName = function() { return this.name; }; Holger Vogelsang Informatik 2 - Einführung in JavaScript 52 Objekte und Vererbung Einführung Da das Attribut prototype ein Objekt ist, können die Funktionen auch direkt in einem neuen Objekt als Schlüssel-/ Wertepaare zugewiesen werden (Kommentare weggelassen): Customer.prototype = { getNo: function() { return this.no; }, getAge: function() { return this.age; }, getName: function() { return this.name; } }; Holger Vogelsang Schlüssel: Methodenname Wert: Funktion Informatik 2 - Einführung in JavaScript 53 Objekte und Vererbung Vererbung Zur Vererbung wird eine Besonderheit der Prototypen verwendet: Einem Prototypen kann ein Vaterprototyp zugewiesen werden. Wird eine Methode nicht im Prototypen des aufgerufenen Objektes gefunden, dann wird sie im Vaterprototypen gesucht. Ist die Methode auch nicht im Vaterprototypen vorhanden, dann wird dessen Vaterprototyp durchsucht. Das Ganze läuft bis zum Typ Object durch. Hier: Vaterprototyp ist der Prototyp der Basisklasse. Beispiel: Jeder Typ ist ein Object. Deswegen können direkt Methoden des Typs Object aufgerufen werden. var c1 = new Customer('Test', 42, -1); console.log(c1.toString()); // Methode von Object Die Methode toString wird nicht im Prototypen von Customer gefunden. Daher wird der Vaterprototyp (hier der von Object) herangezogen. Holger Vogelsang Informatik 2 - Einführung in JavaScript 54 Objekte und Vererbung Vererbung Prototypenverkettung: Object.prototype hat keinen Prototypen Object.getPrototypOf(Object.getPrototypOf(c1)) Customer.prototype Object.getPrototypOf(c1) c1 var c1Proto = Object.getPrototypeOf(c1); var c1ParentProto = Object.getPrototypeOf(c1Proto); var c1ParentParentProto = Object.getPrototypeOf(c1ParentProto); console.log((typeof c1Proto) + ', ' + (c1Proto === Customer.prototype)); // Ausgabe: object, true console.log((typeof c1ParentProto) + ', ' + (c1ParentProto === Object.prototype)); // Ausgabe: object, true console.log((typeof c1ParentParentProto) + ', ' + c1ParentParentProto); // Ausgabe: object, null Holger Vogelsang Informatik 2 - Einführung in JavaScript 55 Objekte und Vererbung Vererbung Wie soll Vererbung umgesetzt werden, ohne dass es Vererbung gibt? Eine Funktion verbindet die Prototypen von Basistyp und abgeleitetem Typ! Vereinfachte Implementierung der Funktion: function _extends(Derived, Base) { var _protoFunction = function() {}; _protoFunction.prototype = Base.prototype; Derived.prototype = new _protoFunction(); } Base.prototype prototype _protoFunction prototype Base prototype Derived Erklärungen: Derived ist der Name der Konstruktorfunktion für den abgeleiteten Typ. Base ist der Name der Konstruktorfunktion für den Basistyp. Der Prototyp des abgeleiteten Typs ist das neue Funktions-Objekt _protoFunction, das seinerseits den Prototypen von Base als eigenen Prototypen besitzt (einem Prototypen kann nicht direkt ein Prototyp zugewiesen werden). Der Name der Funktion _extends startet hier mit einem Unterstrich, um zu zeigen, dass sie nicht direkt zum eigentlichen Programm gehört („Bestandteil der Infrastruktur“). Holger Vogelsang Informatik 2 - Einführung in JavaScript 56 Objekte und Vererbung Vererbung Mit halbwegs aktuellen Browsern (ab ECMAScript 5) kann Object.create verwendet werden: function _extends(Derived, Base) { Derived.prototype = Object.create(Base.prototype); } Erklärung: Object.create erzeugt ein neues Objekt und weist ihm den Prototypen zu, der als Parameter übergeben wurde. Holger Vogelsang Informatik 2 - Einführung in JavaScript 57 Objekte und Vererbung Vererbung Beispielverwendung (Klassendarstellung in UML ist nicht ganz zutreffend es gibt keine Klassen), Basistyp: /** * Konstruktorfunktion des Basistyps * @param val Im Objekt zu speichernder Wert. * @constructor */ function Base(val) { console.log('Base-Konstruktor: ' + val); this.baseValue = val; erzeugt und weist zu } /** * Methode im Basistyp, gibt den intern * gespeicherten Wert auf der Konsole aus. */ Base.prototype.print = function() { console.log('Print in Base: ' + this.baseValue); }; Holger Vogelsang Informatik 2 - Einführung in JavaScript Base +baseValue +Base() +print() Derived +value +Derived() +print() 58 Objekte und Vererbung Vererbung Beispielverwendung, abgeleiteter Typ: /** * Konstruktorfunktion des abgeleiteten Typs. * @param val Im Objekt zu speichernder Wert. * @constructor */ function Derived(val) { // Aufruf des Basiskonstruktors ruft auf Base.call(this, val + 1); console.log('Derived-Konstruktor: ' + val); this.value = val; erzeugt und weist zu } // Vererbungsbeziehung abbilden _extends(Derived, Base); Holger Vogelsang Informatik 2 - Einführung in JavaScript Base +baseValue +Base() +print() Derived +value +Derived() +print() 59 Objekte und Vererbung Vererbung Beispielverwendung, abgeleiteter Typ: /** * Methode im abgeleiteten Typ, gibt den intern * gespeicherten Wert auf der Konsole aus. * Wichtig: Die Methode darf erst nach Herstellen der * Vererbungsbeziehung hinzugefügt werden, weil durch * das Erstellen eines neuen Prototypen in der * Vererbungsfunktion ansonsten diese Methode nicht * mehr Derived zugeordnet wäre. */ Derived.prototype.print = function() { console.log('Print in Derived: ' + this.value); // Aufruf der print-Methode des Basis-Typs. Base.prototype.print.call(this); ruft auf }; Holger Vogelsang Informatik 2 - Einführung in JavaScript Base +baseValue +Base() +print() Derived +value +Derived() +print() 60 Objekte und Vererbung Vererbung WebStorm erkennt die Vererbung im Beispiel: Holger Vogelsang Informatik 2 - Einführung in JavaScript 61 Objekte und Vererbung Vererbung Vergleich mit Java: Das Überschreiben von Methoden ist problemlos möglich. Das Überladen wird nicht unterstützt, da der Methodenname der eindeutige Schlüssel im Objekt ist. Überladen kann recht unelegant nachgebaut werden soll hier nicht besprochen werden. Schnittstellen, Aufzähltypen und statische Methoden sowie statische Attribute können nachgebaut werden soll hier nicht betrachtet werden. Bisher sind alle Daten und Methoden öffentlich, private werden gleich behandelt ist etwas komplizierter. Standard-Methoden ähnlich zu equals und hashCode existieren nicht. Holger Vogelsang Informatik 2 - Einführung in JavaScript 62 Module Übersicht Grafische Oberflächen Übersicht Datenstrukturen ADTs Typinfo., I/O Annotationen JavaScript Prinzipien Holger Vogelsang Layouts Ereignisse Datenstrukturen in Java Laufzeittypinfo. Einstieg Widgets Grafikoperationen Elementare Datenstrukturen Grafikwidgets Effekte, Animationen Iteratoren Hashtabellen Bäume Module Private Daten DOMZugriffe Offene Punkte Graphen Ein-, Ausgabe Funktionen Objekte und Vererbung Informatik 2 - Einführung in JavaScript 63 Module Einführung In Java existieren Pakete zur sauberen Modularisierung. JavaScript kennt so ein Konzept nicht, allerdings kann es mit Funktionen und Objekten nachgebaut werden. Grundidee Closure: Funktionen werden ineinander geschachtelt. Innere Funktionen können auch dann auf die Daten der äußeren zugreifen, wenn diese bereits beendet wurden. Grundidee Namensraum: Ein Namensraum ist ein Objekt, in das Funktionen und Objekte eingefügt werden. Namensräume haben denselben Aufbau wie Pakete in Java. Die Erzeugung der Daten erfolgt in einer anonymen, sofort ausgeführten Funktion. Syntax: (function() { // Mache etwas, der Inhalt ist privat })(); Holger Vogelsang Informatik 2 - Einführung in JavaScript 64 Module Definition Beispiel für den Namensraum de.hska.iwii: /** * Definition der Namensräume mit Hilfe von Objekten. */ var de = {}; de.hska = {}; de.hska.iwii = {}; Es werden drei Objekte erzeugt: de im globalen Namensraum. hska innerhalb des Objekts de. iwii innerhalb des Objekts de.hska. Holger Vogelsang Informatik 2 - Einführung in JavaScript 65 Module Definition Die Zuweisung von Objekten und Funktionen erfolgt an die Namensraumobjekte. Die Erzeugung und Zuweisung erfolgt innerhalb einer Funktion, damit deren Inhalt nicht außerhalb der Funktion sichtbar ist. Die Funktion ist anonym und wird sofort ausgeführt. Sie erhält als Parameter das Namensraum-Objekt, zu dem die Daten hinzugefügt werden sollen. Beispiel für Konfigurationsdaten: /** * Hinzufügen von Objekten zu einem Namensraum. * Alle Daten innerhalb dieser sofort ausgeführten * Funktion sind privat. * @param modul Referenz auf das Namensraum-Objekt */ (function(modul) { var server = { name: 'www.hs-karlsruhe.de', port: 80 }; // Zuweisung an den Namensraum. modul.HSServer = server; Holger Vogelsang Informatik 2 - Einführung in JavaScript 66 Module Definition Und noch ein Funktionsobjekt mit Zugriffsmethoden zum Namensraum hinzufügen: // Konstruktorfunktion sowie weitere Methoden. var cust = function(name, age, no) { this.name = name; this.age = age; this.no = no; }; cust.prototype.getNo = function() { return this.no; }; cust.prototype.getAge = function() { return this.age; }; // Zuweisung an den Namensraum. modul.Customer = cust; })(de.hska.iwii); // Referenz auf den Namensraum Holger Vogelsang Informatik 2 - Einführung in JavaScript 67 Module Verwendung Verwendung des Namensraums: var server = de.hska.iwii.HSServer; console.log(server.name); var cust1 = new de.hska.iwii.Customer('Vogelsang', -1, 42); console.log(cust1.getNo()); Auf die innerhalb der anonymen Funktion erzeugten Daten kann nicht direkt zugegriffen werden, weil eine Funktion einen eigenen Namensraum bildet. Eine direkte import-Anweisung wie in Java für Pakete gibt es nicht. Ausweg: Es kann ein Namensraum-Objekt als Parameter an eine Funktion übergeben werden (siehe Beispiel oben für die anonyme Funktion). Dann kann über diesen Parameter direkt auf den Inhalt des Namensraums zugegriffen werden. Holger Vogelsang Informatik 2 - Einführung in JavaScript 68 Private Daten Übersicht Grafische Oberflächen Übersicht Datenstrukturen ADTs Typinfo., I/O Annotationen JavaScript Prinzipien Holger Vogelsang Layouts Ereignisse Datenstrukturen in Java Laufzeittypinfo. Einstieg Widgets Grafikoperationen Elementare Datenstrukturen Grafikwidgets Effekte, Animationen Iteratoren Hashtabellen Bäume Module Private Daten DOMZugriffe Offene Punkte Graphen Ein-, Ausgabe Funktionen Objekte und Vererbung Informatik 2 - Einführung in JavaScript 69 Private Daten Kapselung Bisher waren alle Daten öffentlich zugreifbar. JavaScript kennt kein Schlüsselwort „private“. Aber die Kapselung kann mit Hilfe von Funktionen erreicht werden. Die privaten Daten sind lokale Variablen im Konstruktor. Die privaten Funktionen werden im Konstruktor definiert. Sie dürfen auf die lokalen Variablen des Konstruktors zugreifen („Closure“), auch wenn dieser beendet ist. Beispiel: function Customer(name, age, no) { this.name = name; this.age = age; this.no = no; // Lokale Variablen im Konstruktor, werden eigentlich // bei Beendigung des Konstruktors gelöscht. var secret = this.no * 2; // Die Definition ist sinnvoll, da this in privaten Methoden nicht // sichtbar ist. var that = this; Holger Vogelsang Informatik 2 - Einführung in JavaScript 70 Private Daten Kapselung // Private Methode (Funktion innerhalb des Konstruktors). // Sie darf auf die lokalen Daten des Konstruktors zugreifen. // Die lokalen Daten bleiben auch nach Beendigung des // Konstruktoraufrufs erhalten (Closure). function getSecretPrivate() { return secret; } } // Damit die private Methode auch außerhalb des // Konstruktors verwendet werden kann, wird sie // am Objekt registriert. this.getSecret = function() { return getSecretPrivate(); }; Auf die private Methode sowie die privaten Daten kann nicht von außerhalb des Objektes zugegriffen werden. Noch besserer Ansatz: Modulidee verwenden soll hier nicht besprochen werden. Holger Vogelsang Informatik 2 - Einführung in JavaScript 71 DOM-Zugriffe Übersicht Grafische Oberflächen Übersicht Datenstrukturen ADTs Typinfo., I/O Annotationen JavaScript Prinzipien Holger Vogelsang Layouts Ereignisse Datenstrukturen in Java Laufzeittypinfo. Einstieg Widgets Grafikoperationen Elementare Datenstrukturen Grafikwidgets Effekte, Animationen Iteratoren Hashtabellen Bäume Module Private Daten DOMZugriffe Offene Punkte Graphen Ein-, Ausgabe Funktionen Objekte und Vererbung Informatik 2 - Einführung in JavaScript 72 DOM-Zugriffe Übersicht Web-Seiten werden intern im Browser durch ein Modell, das Document Object Model (DOM), repräsentiert. Der Baum kann zur Laufzeit durch JavaScriptFunktionen verändert werden. Holger Vogelsang Informatik 2 - Einführung in JavaScript 73 DOM-Zugriffe Auslesen des DOMs Wie erfolgt der Zugriff auf das DOM? document ist eine globale Referenz auf das komplette Dokument. document besitzt Methoden zum Auslesen, Traversieren und Ändern des DOMs. Beispiele: - getElementById(): Sucht nach einem Tag, das eine bestimmte ID besitzt. Das Ergebnis ist das gefundene Element oder null. - getElementsByTagName(): Sucht nach allen Tags eines Typs (z.B. h1). Das Ergebnis ist ein Array aller gefundenen Elemente. - getElementsByClassName(): Sucht alle Elemente, die eine bestimmte CSS-Klasse besitzen. Das Ergebnis ist ein Array aller gefundenen Elemente. Holger Vogelsang Informatik 2 - Einführung in JavaScript 74 DOM-Zugriffe Auslesen des DOMs Beispiel, HTML-Seite: <!DOCTYPE html> <html> <head lang="de"> <meta charset="UTF-8"> <title>DOM-Zugriffe (Auslesen)</title> <script type="text/javascript" src="./js/Dom1.js"></script> </head> <body onload="find('title', 'contents')"> <h1 id="title">Titelzeile</h1> <div id="div1" class="contents">DIV1</div> <div id="div2" class="contents">DIV2</div> </body> </html> onload: Sobald die Seite komplett geladen ist, wird dieses Ereignis vom Browser ausgelöst und die angegebene Funktion aufgerufen. Holger Vogelsang Informatik 2 - Einführung in JavaScript 75 DOM-Zugriffe Auslesen des DOMs Zugehörige JavaScript-Datei: function find(id, className) { var el = document.getElementById(id); console.log(el); el = document.getElementsByClassName(className); for (var index = 0; index < el.length; index++) { console.log(el.item(index)); } } Konsolenausgabe im Firefox: Holger Vogelsang Informatik 2 - Einführung in JavaScript 76 DOM-Zugriffe Ändern des DOMs Auch Schreibzugriffe auf das DOM sind möglich: Es gibt Attribute und Methoden, die auf allen Knoten des DOM definiert sind (z.B. id, className, title). Es gibt für die unterschiedlichen Knoten-Typen (HTML-Tags) weitere, individuelle Attribute und Methoden (z.B. href für a-Tags <a>). Das Attribut innerHTML enthält beispielsweise den HTML-Code des Inhalts eines Tags. Beispiel zu innerHTML: <!DOCTYPE html> <html> <head lang="de"> <meta charset="UTF-8"> <title>DOM-Zugriffe (Modifikation)</title> <script type="text/javascript" src="./js/Dom2.js"></script> </head> <body onload="modify('contents')"> <h1>Titelzeile</h1> <div id="contents"></div> </body> </html> Holger Vogelsang Informatik 2 - Einführung in JavaScript 77 DOM-Zugriffe Ändern des DOMs Zugehörige JavaScript-Datei (fügt eine Tabelle in das div-Tag mit der ID contents ein): function modify(elementId) { var el = document.getElementById(elementId); var innerHTML = '<table><tbody>'; var cnt = 0; for (var row = 0; row < 4; row++) { innerHTML += '<tr style=\'background-color: #0000C0; color: white;\'>'; for (var col = 0; col < 3; col++) { innerHTML += '<td style=\'padding: 4px; text-align: right;\'>' + ++cnt + '</td>'; } innerHTML += '</tr>'; } } innerHTML += '</tbody></table>'; el.innerHTML = innerHTML; Die Tabellenzeilen werden noch blau eingefärbt. Holger Vogelsang Informatik 2 - Einführung in JavaScript eingefügt 78 DOM-Zugriffe Ereignisbehandlung Eine DOM-Dokumentation befindet sich z.B. unter https://developer.mozilla.org/enUS/docs/Web/API/Document_Object_Model, http://www.w3schools.com/jsref/ und http://wiki.selfhtml.org/wiki/JavaScript/Objekte. Ein wichtiges Konzept bei der Arbeit im Browser sind Ereignisse, durch die JavaScriptFunktionen aufgerufen werden, kleine Auswahl: onload am body-Tag: Wenn das Dokument fertig geladen wurde. onclick: Wenn der Anwender auf ein Element im Baum geklickt hat. onresize: Wenn sich die Größe (Breite oder Höhe) des Dokument z.B. durch Verändern der Fenstergröße geändert hat. Werden Daten vom Server nachgeladen, dann geschieht das auch asynchron: Es wird eine Anfrage (Request) an den Server abgesetzt und eine Funktion angegeben, die bei Ereignissen aufgerufen werden soll. Tritt ein Ereignis ein (Antwort vom Server erhalten, Fehler, …), dann wird die registrierte Funktion aufgerufen. Bei synchronem (also wartendem Zugriff) wäre der Browser ansonsten solange blockiert. Holger Vogelsang Informatik 2 - Einführung in JavaScript 79 DOM-Zugriffe Ereignisbehandlung Beispiel zur zeitgesteuerten Durchführung von Aktionen (setInterval ruft alle x Sekunden eine parameterlose Funktion auf): <!DOCTYPE html> <html> <head lang="de"> <meta charset="UTF-8"> <title>DOM-Zugriffe (Zeitgesteuert)</title> <script type="text/javascript" src="./js/Dom3.js"></script> </head> <body onload="setInterval(function(){modify('contents');}, 1000)"> <h1>Titelzeile</h1> <div id="contents"> Huhu </div> </body> </html> Holger Vogelsang Informatik 2 - Einführung in JavaScript 80 DOM-Zugriffe Ereignisbehandlung Beispiel (JavaScript-Datei, setzt die Hintergrundfarbe des angegebenen Elements zyklisch neu): var colors = ['lightblue', 'silver', 'lightgreen']; var colorIndex = 0; function modify(elementId) { var el = document.getElementById(elementId); } if (colorIndex == colors.length) { colorIndex = 0; } el.setAttribute('style', 'background-color: ' + colors[ colorIndex++ ] + ';'); console.log(el.getAttribute('style')); Es kann noch mehr mit dem DOM „angestellt“ werden nicht Bestandteil der Vorlesung. Holger Vogelsang Informatik 2 - Einführung in JavaScript 81 DOM-Zugriffe Ausblick Ist das nicht sehr mühsam? Wie sieht es mit Browserabhängigkeiten aus? Bibliotheken vereinfachen die Arbeit, Auswahl: jQuery: http://jquery.com/ Bootstrap: http://getbootstrap.com/ AngularJS: https://angularjs.org/ Holger Vogelsang Informatik 2 - Einführung in JavaScript 82 Ende Holger Vogelsang Informatik 2 - Einführung in JavaScript 83