[[PageOutline(2-5)]]
= !JavaScript =
== Einbindung in HTML-Seiten ==
Leseempfehlung: [[http://wiki.selfhtml.org/wiki/JavaScript/Tutorials/Einbindung_in_HTML|selfhtml Tutorial Einbindung in HTML]]
== Sprachelemente ==
Leseempfehlung: [[http://wiki.selfhtml.org/wiki/JavaScript/Sprachelemente|selfhtml JavaScript Sprachelemente]]
== Objekte in !JavaScript ==
In !JavaScript werden keine Klasse benötigt, um Objekte zu erzeugen. Statt dessen können Objekte mit sogenannten Objektliteralen erzeugt werden:
Tip: Führen Sie die folgenden Anweisungen in der Console von Chrome aus und beobachten Sie die Ausgaben:
Das leere Objekt ist das einfachste Objekt:
{{{
#!javascript
> var o = {}
> o
Object {}
}}}
Einige Funktionen und Attribute wurden vom Prototypen `Object` übernommen, wie z. B. die Funktion `toString`:
{{{
#!javascript
> o.toString // Anzeige des Attributs toString (Funktionen sind Attribute)
function toString() { [native code] }
> o.toString() // Aufruf der Funktion toString
"[object Object]"
}}}
Objekte ähneln assoziativen Arrays, die Attribute können als Schlüssel-/Wert-Paare verstanden werden. Objekte können auch direkt mit Attributen angelegt werden:
{{{
#!javascript
> var susi = {vorname: "Susi", nachname: "Sonne", alter: 23};
> susi.nachname
"Sonne"
}}}
Attribute (auch ererbte) können geändert werden. Dabei kann der Typ sich ändern. Beispiel: das geerbte Attribut `toString` wird mit einer Zahl belegt und danach mit einer Funktion. Innerhalb von Objekten gibt es das Schlüsselwort `this`, mit dem auf die objekteigenen Attribute und Funktionen zugegriffen werden kann.
{{{
#!javascript
> susi.toString = 42 // !!! können toString mit irgendwas anderem ersetzen
> susi.toString
42
> susi.toString = function() {
return this.vorname + " " + this.nachname +
" (" + this.alter + ")";
}
function() { ... }
> susi.toString()
"Susi Sonne (23)"
}}}
=== Objekte mit gleichen Eigenschaften ===
Häufig werden in Informationssystemen mehrere Objekte desselben Typs verwendet. Die Objekte haben denselben Satz an Attributen und dieselben Funktionen. In anderen Sprachen wie z. B. Java spricht man von Klassen.
Gleichartige Objekte können in Javascript auf verschiedene Weise erzeugt werden. In Java dagegen können Objekte nur erzeugt werden, indem der Konstruktor einer Klasse aufgerufen wird.
==== Klonen vorhandener Objekte ====
Mit der `for-in`-Schleife kann über Attribute von Objekten iteriert werden. Auf die Werte der Attribute kann mittels eckigen Klammern `[]` wie in einem Array zugegriffen werden:
{{{
#!javascript
> for (var attr in susi) {console.log(attr + ": " + susi[attr]);}
vorname: Susi
nachname: Sonne
alter: 23
toString: function () {
return this.vorname + " " + this.nachname +
" (" + this.alter + ")";
}
}}}
Diese Möglichkeit lässt sich nutzen, um Objekte rekursiv zu kopieren:
{{{
#!javascript
function clone(obj) {
// testen, ob es sich um ein Objekt handelt
// Abbruchbedingung der Rekursion
if ((obj === null) || (typeof obj !== "object")) {
// nein: den Wert einfach zurückgeben
return obj;
}
// sonst: Klon dieses Objekts anlegen
var newObj = {};
// Über die Attribute iterieren und diese clonen
// Rekursionsschritt
for (var attr in obj) {
newObj[attr] = clone(obj[attr]);
}
return newObj;
}
}}}
Zur Demonstration kann das Objekt `susi` um ein weiteres Attribut, `adresse`, das selbst wieder ein Objekt ist, erweitert werden:
{{{
#!javascript
> susi.adresse = {strasse: "Friedrich-Heinrich-Allee 25", plz: "47475", ort: "Kamp-Lintfort"}
Object {strasse: "Friedrich-Heinrich-Allee 25", plz: "47475", ort: "Kamp-Lintfort"}
}}}
Wenn die Funktion `clone` und alle anderen Anweisungen in einem `
}}}
Im Attribut onclick des Elements wird !JavaScript-Code notiert. Dabei kann es sich sowohl direkt um den fachlichen Code (siehe d1) als auch um einen Funktionsaufruf (siehe d2) handeln.
Registrierung mittels DOM-Manipulation über die Funktion `addEventListener`:
{{{
#!htm
...
Message über benannten Eventhandler
Message über anonyme Funktion
}}}
Im ersten Fall wird die Funktion `clickD2` aus dem vorherigen Codebeispiel als Eventhandler für das div d3 registriert. Hinter dem Funktionsnamen dürfen keine runden () Klammern notiert werden, da das Funktionsobjekt selbst übergeben werden soll. Mit runden Klammern würde statt dessen die Funktion `clickD2()` aufgerufen werden und deren Rückgabewert (in diesem Fall `undefined`) als Eventhandler registriert werden.
Im zweiten Fall (d4) wird eine anonyme Funktion als Eventhandler registriert. Zu beachten sind hier die korrekte Klammerung der in den Aufruf von `addEventListener` eingeschachtelten Funktionsdefinition sowie das Semikolon am Ende des Aufrufs.
Falls die beim Registrieren eingebundene Funktion selbst kein Eventhandler ist, sondern einen zurückliefert, kann natürlich auch ein Funktionsaufruf erfolgen:
{{{
#!javascript
function clickD3() {
alert("Aufruf clickD3");
return function() {
alert("generierter Eventhandler");
};
}
}}}
Die Registrierung erfolgt dann mit dem Handler, der vom Funktionsaufruf `clickD3()` zurückgeliefert wird (beachte die runden Klammern hinter clickD3):
{{{
#!javascript
document.getElementById("d3").addEventListener("click", clickD3());
}}}
Der erste Parameter eines Eventhandlers ist standardmäßig das Eventobjekt. Wenn der Eventhandler mit einem Parameter definiert wird, kann darüber auf die Eigenschaften des Events zugegriffen werden. Dies kann z. B. für Spiele oder Grafikeditoren sinnvoll sein:
{{{
#!javascript
document.addEventListener("click", function(e){
alert("x: " + e.clientX + " / y: " + e.clientY);
});
}}}
Events lassen sich also auch direkt mit dem gesamten Dokument als Event Target registrieren, nicht nur für einzelne HTML-Elemente.
Es können auch mehrere Events an demselben Element registriert werden und es können mehrere Eventhandler durch ein und dieselbe Benutzeraktion ausgelöst werden. Beispielsweise wird jeder Klick auf eines der div-Elemente d1 bis d4 dazu führen, dass auch der Eventhandler für den Click am Dokument ausgeführt wird.
== JSON - !JavaScript Object Notation ==
JSON ist eine als Zeichenkette serialisierte Darstellung eines Objektes, die menschenlesbar ist und zum Datenaustausch verwendet werden kann. Das Format ist interoperabel. Es ist nicht auf !JavaScript beschränkt, es lassen sich beispielsweise auch JSON-Objekte zwischen PHP Skripten austauschen oder zwischen einem !JavaScript und einem PHP-Programm.
Eine JSON-Zeichenkette lässt sich aus einem Objekt mittels JSON.stringify() erzeugen:
{{{
#!javascript
> var bm = {name: "Bohrmaschine", preis: 73.99}
> bm
Object {name: "Bohrmaschine", preis: 73.99}
> var json = JSON.stringify(bm)
> json
"{"name":"bohrmaschine","preis":73.99}"
}}}
Mit der Funktion JSON.parse() lässt sich auf dem umgekehrten Weg ein !JavaScript-Objekt aus der JSON-Zeichenkette erezugen:
{{{
#!javascript
> var bm2 = JSON.parse(json)
> bm2
Object {name: "Bohrmaschine", preis: 73.99}
}}}
JSON-Zeichenketten enthalten nur die datenartigen Attribute der Objekte. Funktionsattribute werden nicht in die Zeichenkette kodiert:
{{{
#!javascript
> bm.toString = function() {console.log(this.name + " " + this.preis);}
> bm.toString()
bohrmaschine 73.99
> var json = JSON.stringify(bm)
> json
"{"name":"bohrmaschine","preis":73.99}"
> var bm2 = JSON.parse(json)
> bm2.toString()
"[object Object]"
}}}
Die Funktion `toString` ist in der JSON-Zeichenkette nicht enthalten. Statt dessen wird die geerbte Funktion `toString` des Objekts Object ausgeführt.
Attribute, die selbst Objekte sind, und Arrays werden rekursiv in die JSON-Zeichenkette eingebaut:
{{{
#!javascript
> var ww = {name: "Wasserwaage", preis: 25.00}
> var bestellung = {datum: "21.05.2017", kunde: "Susi Sonne", artikel: [bm, ww]}
> bestellung
Object {datum: "21.05.2017", kunde: "Susi Sonne", artikel: Array(2)}
> var json = JSON.stringify(bestellung)
> json
"{"datum":"21.05.2017","kunde":"Susi Sonne","artikel":[{"name":"bohrmaschine","preis":73.99},{"name":"Wasserwaage","preis":25}]}"
}}}
=== Workaround für nicht eingebundene Funktionen ===
Falls es erforderlich ist, dass Objekte aus JSON-Zeichenketten zusammen mit den zugehörigen Funktionen wiederhergestellt werden, kann ein Workaround mit einer Erzeugerfunktion implementiert werden. Dieser Workaround erfordert die Kenntnis der ursprünglichen Konstruktorfunktion des Objekts:
{{{
#!CodeExample
## title = JSON Beispiel
## repo = Web_Quellcode_FP
## path = /vorlesung/javascript/json.html
#!html
}}}
Die Funktion `Bestellung.createFromJSON` kann nun verwendet werden, um aus JSON-Zeichenketten, die Bestellung-Objekte enthalten, wieder "echte" Bestellung-Objekte zu erzeugen. Dieses Verfahren funktioniert nur bei überschaubarer Komplexität der betroffenen Objekte und bei Zugang zu den Konstruktorfunktionen.
Beispiel zur Verwendung (Laden Sie die Datei [[source:/Web_Quellcode_FP/vorlesung/javascript/json.html|json.html]] im Browser und führen Sie die folgenden Anweisungen in der Konsole aus):
{{{
#!javascript
> var bm = new Artikel("Bohrmaschine", 73.99)
> bm.toString()
"Bohrmaschine 73.99"
> var ww = new Artikel("Wasserwaage", 25)
> ww.toString()
"Wasserwaage 25"
> var b = new Bestellung("21.05.2017", "Willi Wacker")
> b.addArtikel(bm)
> b.addArtikel(ww)
> b
Bestellung {datum: "21.05.2017", kunde: "Willi Wacker", artikel: Array(2), addArtikel: function}
> var js = JSON.stringify(b)
> js
"{"datum":"21.05.2017","kunde":"Willi Wacker","artikel":[{"name":"Bohrmaschine","preis":73.99},{"name":"Wasserwaage","preis":25}]}"
> var b2 = JSON.parse(js)
> b2
Object {datum: "21.05.2017", kunde: "Willi Wacker", artikel: Array(2)}
}}}
Das aus der JSON-Zeichenkette neu erstellte Objekt enthält keine Funktionen. Der Aufruf von `addArtikel` schlägt fehl:
{{{
#!javascript
> b2.addArtikel(ww)
VM203:1 Uncaught TypeError: b2.addArtikel is not a function
at :1:4
(anonymous) @ VM203:1
}}}
Werden dagegen über `Bestellung.createFromJSON()` die ursprünglichen Konstruktorfunktionen verwendet, sind auch die Funktionen vorhanden und können aufgerufen werden:
{{{
#!javascript
> var b2 = Bestellung.createFromJSON(js)
> b2.addArtikel(ww)
> b2
Bestellung {datum: "21.05.2017", kunde: "Willi Wacker", artikel: Array(3), addArtikel: function}
}}}
== DOM Manipulation mit jQuery ==
[[https://jquery.com|jQuery]] ist ein !JavaScript-Framework, das die DOM-Manipulation, insbesondere die Änderung von Darstellungseigenschaften der Oberflächenelemente stark vereinfacht.
Mit jQuery lassen sich mehrere Elemente selektieren, die modifiziert werden sollen. Die Beispiele beziehen sich auf den folgenden HTML-Ausschnitt aus [[source:Web_Quellcode_FP/vorlesung/javascript/jquery.html|jquery.html]]:
{{{
#!htm
...
Bohrmaschine
Binford Tools
73.99
Wasserwaage
Wasserversorgung Kamp-Lintfort
25.00
}}}
Die Aufrufe des jQuery-Frameworks beginnen meist mit einem Aufruf des Selektors. Der Selektoraufruf folgt der Syntax `$("selektor")` wobei `selektor` ein beliebiger CSS-Selektor ist. Als Ergebnis des reinen Selektoraufrufs wird ein Array mit allen selektierten Elementen zurückgegeben:
{{{
#!javascript
> $("#d1")
[div#d1]
> $("div")
(3) [div#d1, div#d2, div#d3, prevObject: jQuery.fn.init(1)]
}}}
Auf den Ergebnissen lassen sich direkt weitere Aktionen zur DOM-Manipulation ausführen:
{{{
#!javascript
> $("#d1").addClass("rot");
[div#d1.rot]
> $("div").addClass("gruen");
(3) [div#d1.rot.gruen, div#d2.gruen, div#d3.gruen, prevObject: jQuery.fn.init(1)]
}}}
Neue Elemente lassen sich mit `append`in das DOM einfügen:
{{{
#!javascript
> $("#p3").append("Ich bin neu hier")
[p#p3]
> $("#p3 span")
[span, prevObject: jQuery.fn.init(1)]
> $("#p3 span").attr("id", "s1")
[span#s1, prevObject: jQuery.fn.init(1)]
> $("#s1").addClass("blau")
[span#s1.blau]
}}}