Changes between Initial Version and Version 1 of skript/javascript


Ignore:
Timestamp:
Oct 14, 2018, 11:17:50 AM (6 years ago)
Author:
tracadmin
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • skript/javascript

    v1 v1  
     1[[PageOutline(2-5)]]
     2
     3= !JavaScript =
     4
     5== Einbindung in HTML-Seiten ==
     6
     7Leseempfehlung: [[http://wiki.selfhtml.org/wiki/JavaScript/Tutorials/Einbindung_in_HTML|selfhtml Tutorial Einbindung in HTML]]
     8
     9== Sprachelemente ==
     10Leseempfehlung: [[http://wiki.selfhtml.org/wiki/JavaScript/Sprachelemente|selfhtml JavaScript Sprachelemente]]
     11
     12== Objekte in !JavaScript ==
     13
     14In !JavaScript werden keine Klasse benötigt, um Objekte zu erzeugen. Statt dessen können Objekte mit sogenannten Objektliteralen erzeugt werden:
     15
     16Tip: Führen Sie die folgenden Anweisungen in der Console von Chrome aus und beobachten Sie die Ausgaben:
     17
     18Das leere Objekt ist das einfachste Objekt:
     19
     20{{{
     21#!javascript
     22> var o = {}
     23> o
     24Object {}
     25}}}
     26
     27Einige Funktionen und Attribute wurden vom Prototypen `Object` übernommen, wie z. B. die Funktion `toString`:
     28
     29{{{
     30#!javascript
     31> o.toString    // Anzeige des Attributs toString (Funktionen sind Attribute)
     32function toString() { [native code] }
     33
     34> o.toString()  // Aufruf der Funktion toString
     35"[object Object]"
     36}}}
     37
     38Objekte ähneln assoziativen Arrays, die Attribute können als Schlüssel-/Wert-Paare verstanden werden. Objekte können auch direkt mit Attributen angelegt werden:
     39
     40{{{
     41#!javascript
     42> var susi = {vorname: "Susi", nachname: "Sonne", alter: 23};
     43> susi.nachname
     44"Sonne"
     45}}}
     46
     47Attribute (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.
     48
     49{{{
     50#!javascript
     51> susi.toString = 42  // !!! können toString mit irgendwas anderem ersetzen
     52> susi.toString
     5342
     54
     55> susi.toString = function() {
     56      return this.vorname + " " + this.nachname +
     57      " (" + this.alter + ")";
     58  }
     59function() { ... }
     60
     61> susi.toString()
     62"Susi Sonne (23)"
     63}}}
     64
     65=== Objekte mit gleichen Eigenschaften ===
     66Hä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.
     67
     68Gleichartige 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.
     69
     70==== Klonen vorhandener Objekte ====
     71Mit 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:
     72
     73{{{
     74#!javascript
     75> for (var attr in susi) {console.log(attr + ": " + susi[attr]);}
     76vorname: Susi
     77nachname: Sonne
     78alter: 23
     79toString:  function () {
     80      return this.vorname + " " + this.nachname +
     81      " (" + this.alter + ")";
     82  }
     83}}}
     84
     85Diese Möglichkeit lässt sich nutzen, um Objekte rekursiv zu kopieren:
     86
     87{{{
     88#!javascript
     89function clone(obj) {
     90    // testen, ob es sich um ein Objekt handelt
     91    // Abbruchbedingung der Rekursion
     92        if ((obj === null) || (typeof obj !== "object")) {
     93            // nein: den Wert einfach zurückgeben
     94                return obj;
     95        }
     96       
     97        // sonst: Klon dieses Objekts anlegen
     98        var newObj = {};
     99        // Über die Attribute iterieren und diese clonen
     100        // Rekursionsschritt
     101        for (var attr in obj) {
     102                newObj[attr] = clone(obj[attr]);
     103        }
     104        return newObj;
     105}
     106}}}
     107
     108Zur Demonstration kann das Objekt `susi` um ein weiteres Attribut, `adresse`, das selbst wieder ein Objekt ist, erweitert werden:
     109
     110{{{
     111#!javascript
     112> susi.adresse = {strasse: "Friedrich-Heinrich-Allee 25", plz: "47475", ort: "Kamp-Lintfort"}
     113Object {strasse: "Friedrich-Heinrich-Allee 25", plz: "47475", ort: "Kamp-Lintfort"}
     114}}}
     115
     116Wenn die Funktion `clone` und alle anderen Anweisungen in einem `<script>`-Element einer HTML notiert werden, kann diese Seite in Chrome geladen und die Funktion `clone` im Debugger beobachtet werden. Es zeigt sich, dass die Rekursion bei den primitiven Attributen `vorname`, `nachname` und `alter` in der Abbruchbedingung endet, beim Attribut `adresse` die Schleife jedoch für dessen Attribute `strasse`, `plz` und `ort` erneut ausgeführt wird. Im Ergebnis entsteht ein neues Objekt als echte Kopie des ursprünglichen Objekts `susi`:
     117
     118{{{
     119#!javascript
     120> var willy = clone(susi);
     121> willy
     122Object {vorname: "Susi", nachname: "Sonne", alter: 23, adresse: Object, toString: function}
     123}}}
     124
     125An dieser Stelle fällt auf, dass das Objekt `willy` eine echte Kopie des Objektes `susi` ist. Zur Erzeugung strukturell gleicher, aber inhaltlich verschiedener Objekte ist das Klonen daher eher unvorteilhaft, da alle Attribute explizit von außen neu gesetzt werden müssen:
     126
     127{{{
     128#!javascript
     129> willy.vorname = "Willy"
     130> willy.nachname = "Winzig"
     131> willy.alter = 21
     132> willy.adresse.strasse = "Marie-Curie-Straße 1"
     133> willy.adresse.plz = "47533"
     134> willy.adresse.ort = "Kleve"
     135> willy
     136Object {vorname: "Willy", nachname: "Winzig", alter: 21, adresse: Object, toString: function}
     137}}}
     138
     139==== Prototypen ====
     140Ein Objekt lässt sich als Prototyp eines anderen Objektes festlegen. Dazu wird das Attribut `prototype`, über das jedes Objekt verfügt, gesetzt. Hier entsteht im Gegensatz zum Klonen eine Vererbungshierarchie.
     141
     142{{{
     143#!javascript
     144function extendObject(obj) {
     145    function C() {}
     146    C.prototype = obj;
     147    return new C();
     148}
     149}}}
     150
     151Ein neues Objekt lässt sich nun unter Verwendung eines bestehenden Objektes erzeugen:
     152
     153{{{
     154#!javascript
     155> var willy = extendObject(susi)
     156> willy.toString()
     157"Susi Sonne (24)"
     158}}}
     159
     160Auch hier lassen sich jedoch keine Attributwerte übergeben, sondern müssen im Nachgang explizit gesetzt werden. Strukturelle Änderungen am originalen Objekt (dem Prototypen) wirken sich direkt auf alle Objekte aus, die auf dem Prototypen basieren:
     161
     162{{{
     163#!javascript
     164> willy.vorname = "Willy"
     165> willy.toString()
     166"Willy Sonne (24)"
     167
     168> susi.increaseAlter = function() {this.alter++;}
     169> willy.increaseAlter()
     170> willy.toString()
     171"Willy Sonne (25)"
     172}}}
     173
     174==== Erzeugerfunktion ====
     175Wird die Erstellung mittels Objektliteral in einer Funktion gekapselt, spricht man von einer Erzeugerfunktion:
     176
     177{{{
     178#!javascript
     179function createPerson(vorname, nachname, alter) {
     180    return {
     181        vorname: vorname,
     182        nachname: nachname,
     183        alter: alter,
     184        toString: function() {
     185            return this.vorname + " " + this.nachname + " (" + this.alter + ")";
     186        }
     187    };
     188}
     189}}}
     190
     191Dieser Funktion lassen sich Attributwerte als Parameter übergeben, jedoch entsteht keine Vererbungshierarchie - es sei denn, es wird auch ein Parameter für das Attribut `prototype` übermittelt und in der Funktion gesetzt.
     192
     193Das Objekt wird dann mittels Funktionsaufruf erzeugt:
     194
     195{{{
     196#!javascript
     197> var susi = createPerson("Susi", "Sonne", 24)
     198> susi
     199Object {vorname: "Susi", nachname: "Sonne", alter: 24, toString: function}
     200
     201> susi.toString()
     202"Susi Sonne (24)"
     203}}}
     204
     205==== Konstruktorfunktion ====
     206Konstruktorfunktionen kommen strukturell Java-Klassen mit Konstruktoren am nächsten. Sie werden üblicherweise entsprechend der [[https://google.github.io/styleguide/javascriptguide.xml#Naming|gängigen Namenskonventionen]] in [[https://de.wikipedia.org/wiki/Binnenmajuskel#Programmiersprachen|CamelCase]], beginnend mit einem Großbuchstaben, benannt. Konstruktorfunktionen werden üblicherweise in eigene .js-Dateien ausgelagert; im folgenden Beispiel also Person.js. Der Konstruktor liefert das erzeugte Objekt implizit als Rückgabewert, eine Angabe von `return this;` ist also nicht erforderlich:
     207
     208{{{
     209#!javascript
     210function Person(vn, nn, alter) {
     211    // Attribute setzen
     212    this.vorname = vn;
     213    this.nachname = nn;
     214    this.alter = alter;
     215       
     216    // Methoden
     217    this.toString = function() {
     218        return this.vorname + " " + this.nachname + " (" + this.alter + ")";
     219    };
     220}
     221}}}
     222
     223Der Aufruf der Konstruktorfunktion mit dem Schlüsselwort `new` führt dann zur Objekterzeugung:
     224
     225{{{
     226#!javascript
     227> var willy = new Person("Willy", "Winzig", 21)
     228> willy.toString()
     229"Willy Winzig (21)"
     230}}}
     231
     232==== Schutz vor fehlerhafter Verwendung ====
     233
     234Bei der Verwendung von Konstruktorfunktionen ist darauf zu achten, dass diese prinzipiell auch ohne `new` aufgerufen werden können. Dann wird das globale Objekt (im Browser: `window`) um die aufgeführten Attribute erweitert, aber kein neues Objekt erzeugt. Es ist ein typischer Fehler, dass `new` vergessen wird:
     235
     236{{{
     237#!javascript
     238> var alex = Person("Alex", "Schmidt", 31)
     239> alex
     240undefined
     241
     242> window.vorname
     243"Alex"
     244}}}
     245
     246Dies lässt sich durch eine Schutzmaßnahme im Konstruktor selbst verhindern:
     247
     248{{{
     249#!javascript
     250function Person(vn, nn, alter) {
     251    // Welchen Typ hat this?
     252    // Schützt den Konstruktor vor Aufruf ohne new
     253    // ggf. erfolgt einmalig rekursiver Aufruf des
     254    // Konstruktors mit new
     255    if (!(this instanceof Person)) {
     256        return new Person(vn, nn, alter);
     257    }
     258
     259    // Attribute setzen
     260    this.vorname = vn;
     261    this.nachname = nn;
     262    this.alter = alter;
     263       
     264    // Methoden
     265    this.toString = function() {
     266        return this.vorname + " " + this.nachname + " (" + this.alter + ")";
     267    };
     268}
     269}}}
     270
     271Der Aufruf ohne `new` führt nun dazu, dass der Konstruktor sich selbst korrekt mit `new` aufruft und das neu erzeugte Objekt zurückliefert:
     272
     273{{{
     274#!javascript
     275> var alex = Person("Alex", "Schmidt", 33)
     276> alex
     277Person {vorname: "Alex", nachname: "Schmidt", alter: 33, toString: function}
     278}}}
     279
     280Nichtsdestotrotz sollte beim Programmieren darauf geachtet werden, stets `new` zu verwenden, um Problemen mit Konstruktorfunktionen, die nicht über einen derartigen Schutz verfügen, vorzubeugen.
     281
     282==== Sichtbarkeit von Attributen ====
     283
     284Alle mit `this.` notierten Attribute und Funktionen sind öffentlich zugänglich. In Konstruktorfunktionen lassen sich auch private Attribute und Attribute angeben, indem `this.` weggelassen wird. Statt dessen werden lokale Attribute mit `var` definiert:
     285
     286{{{
     287#!javascript
     288function Person(vn, nn, alter) {
     289
     290    ...
     291       
     292    this.toString = function() {
     293        count();
     294        return this.vorname + " " + this.nachname + " (" + this.alter + ")";
     295    };
     296       
     297    // privater Zähler mit Zählfunktion
     298    var counter = 0;
     299    var count = function() {
     300        counter++;
     301    };
     302       
     303    // öffentlicher lesender Zugriff
     304    this.getCounter = function() {
     305        return counter;
     306    };
     307}
     308}}}
     309
     310=== Fazit Objekterzeugung ===
     311Wegen der genannten Probleme bei den anderen Varianten sind Erzeugerfunktionen und Konstruktorfunktionen zu bevorzugen, wobei die Konstruktorfunktion für fachlich komplexe Objekte möglicherweise bessere Übersichtlichkeit bietet.
     312
     313== Tip zur Verwendung von Testdaten ==
     314Testdaten lassen sich im Quellcode ganz einfach als Variable definieren:
     315
     316{{{
     317#!javascript
     318// Array von Personen
     319var personen = [
     320    {
     321        vorname: "Susi",
     322        nachname: "Sonne",
     323        alter: 24,
     324        adresse: {
     325            strasse: "Friedrich-Heinrich-Allee 25",
     326            plz: "47475",
     327            ort: "Kamp-Lintfort"
     328        }
     329    },
     330    {
     331        vorname: "Willy",
     332        nachname: "Winzig",
     333        alter: 21,     
     334            adresse: {
     335            strasse: "Marie-Curie-Straße 1",
     336            plz: "47533",
     337            ort: "Kleve"
     338        }
     339    }
     340];
     341
     342> personen[0]
     343Object {vorname: "Susi", nachname: "Sonne", alter: 24, adresse: Object}
     344}}}
     345
     346== Eventhandling ==
     347
     348Die im 1. Semester entwickelten Java-Konsolenprogramme haben als Einstiegspunkt eine `main` Methode und laufen ohne größere Unterbrechungen bis zum Ende durch. Dabei wird eine Berechnung o. ä. ausgeführt und das Ergebnis ausgegeben. Das folgende UML-Sequenzdiagramm illustriert diesen Ablauf beispielhaft:
     349
     350{{{
     351#!html
     352<style>
     353.drawing {
     354  stroke: black;
     355  stroke-width: 2px;
     356}
     357</style>
     358<svg width="320px" class="drawing" viewbox="-1 -1 322 282" preserveAspectRatio="xMinYMin">
     359
     360 <g id="lifeline">
     361  <rect fill="none" x="0" y="0" width="100" height="30" />
     362  <line x1="50" y1="30" x2="50" y2="280" stroke-dasharray="3,3" />
     363 </g>
     364
     365 <use x="110" y="0" xlink:href="#lifeline" />
     366 <use x="220" y="0" xlink:href="#lifeline" />
     367
     368 <text x="33" y="20" stroke-width="0.5">main</text>
     369 <text x="127" y="20" stroke-width="0.5">methode1</text>
     370 <text x="237" y="20" stroke-width="0.5">methode2</text>
     371
     372 <rect x="40" y="30" width="20" height="50" fill="white" />
     373 <rect x="40" y="240" width="20" height="40" fill="white" />
     374
     375 <rect x="150" y="80" width="20" height="30" fill="white" />
     376 <rect x="150" y="190" width="20" height="50" fill="white" />
     377
     378 <rect x="260" y="110" width="20" height="80" fill="white" />
     379
     380 <defs>
     381  <g id="arrow">
     382   <line x1="0" y1="0" x2="90" y2="0" />
     383   <line x1="80" y1="-5" x2="90" y2="0" />
     384   <line x1="80" y1="5" x2="90" y2="0" />
     385  </g>
     386 </defs>
     387
     388 <use x="60" y="80" xlink:href="#arrow" />
     389 <use x="170" y="110" xlink:href="#arrow" />
     390
     391 <use x="170" y="190" xlink:href="#arrow" transform="scale(180,215,190)" />
     392
     393 <use x="60" y="240" xlink:href="#arrow" transform="rotate(180,105,240)" />
     394
     395  Ihr Browser beherrscht kein SVG.
     396</svg>
     397}}}
     398
     399Programme mit grafischen Benutzeroberflächen kombinieren solche fachlich eher kleinen Programmteile zu größeren Applikationen, die mit dem User interagieren. Diese Programme laufen üblicherweise nicht permanent, sondern reagieren auf Benutzereingaben. Damit eine Benutzereingabe die Ausführung von Programmteilen (z. B. eine Suche) auslösen kann, muss es ein Stück Programmcode geben, das ausgeführt wird, sobald die Benutzeraktion eintritt. Das Programm "wartet" gewissermaßen andauernd darauf, dass der Benutzer Ereignisse auslöst. Üblicherweise ist die Runtime der Programmteil, der auf die Benutzeraktionen "wartet". Die Programmteile, die auf die Benutzeraktionen mit einer fachlichen Funktion reagieren nennt man Eventhandler. Ein Eventhandler ist eine Funktion, die von der Runtime (dem Browser) aufgerufen wird, sobald die zugehörige Benutzeraktion (z. B. Mausklick) eingetreten ist. Im folgenden Beispiel sind die Funktionen 1, 2 und 3 Eventhandler, die von der Runtime asynchron aufgerufen werden, sobald ein Ereignis eintritt. Bei einem asynchronen Aufruf wartet der Aufrufer nicht darauf, dass der Aufruf zurückkehrt:
     400
     401{{{
     402#!html
     403<style>
     404.drawing {
     405  stroke: black;
     406  stroke-width: 2px;
     407}
     408</style>
     409<svg width="430px" class="drawing" viewbox="-1 -1 432 282" preserveAspectRatio="xMinYMin">
     410
     411 <g id="lifeline">
     412  <rect fill="none" x="0" y="0" width="100" height="30" />
     413  <line x1="50" y1="30" x2="50" y2="280" stroke-dasharray="3,3" />
     414 </g>
     415
     416 <use x="110" y="0" xlink:href="#lifeline" />
     417 <use x="220" y="0" xlink:href="#lifeline" />
     418 <use x="330" y="0" xlink:href="#lifeline" />
     419
     420 <text x="22" y="20" stroke-width="0.5">Runtime</text>
     421 <text x="127" y="20" stroke-width="0.5">funktion1</text>
     422 <text x="237" y="20" stroke-width="0.5">funktion2</text>
     423 <text x="347" y="20" stroke-width="0.5">funktion3</text>
     424
     425 <rect x="40" y="40" width="20" height="220" fill="white" />
     426
     427 <rect x="150" y="80" width="20" height="30" fill="white" />
     428 <rect x="150" y="130" width="20" height="40" fill="white" />
     429
     430 <rect x="260" y="50" width="20" height="20" fill="white" />
     431 <rect x="260" y="110" width="20" height="20" fill="white" />
     432
     433 <rect x="370" y="210" width="20" height="30" fill="white" />
     434
     435 <defs>
     436  <g id="arrow">
     437   <line x1="0" y1="0" x2="90" y2="0" />
     438   <line x1="80" y1="-5" x2="90" y2="0" />
     439   <line x1="80" y1="5" x2="90" y2="0" />
     440  </g>
     441 </defs>
     442
     443 <use x="60" y="50" xlink:href="#dashedarrow" transform="scale(2,1)"/>
     444  <g transform="translate(60,50)">
     445   <line x1="0" y1="0" x2="200" y2="0" stroke-dasharray="3,3" />
     446   <line x1="190" y1="-5" x2="200" y2="0" />
     447   <line x1="190" y1="5" x2="200" y2="0" />
     448  </g>
     449  <g transform="translate(60,80)">
     450   <line x1="0" y1="0" x2="90" y2="0" stroke-dasharray="3,3" />
     451   <line x1="80" y1="-5" x2="90" y2="0" />
     452   <line x1="80" y1="5" x2="90" y2="0" />
     453  </g>
     454 <use x="170" y="110" xlink:href="#arrow" />
     455 <use x="170" y="130" xlink:href="#arrow" transform="rotate(180,215,130)" />
     456  <g transform="translate(60,210)">
     457   <line x1="0" y1="0" x2="310" y2="0" stroke-dasharray="3,3" />
     458   <line x1="300" y1="-5" x2="310" y2="0" />
     459   <line x1="300" y1="5" x2="310" y2="0" />
     460  </g>
     461
     462  Ihr Browser beherrscht kein SVG.
     463</svg>
     464}}}
     465
     466Damit die Runtime den korrekten Eventhandler aufrufen kann, muss der Eventhandler zuerst bei der Runtime registriert werden. Im Browser kann die Registrierung von Eventhandlern auf verschiedene Arten erfolgen. Für die Registrierung eines Eventhandlers sind diese Informationen erforderlich:
     467
     468* Das Ereignis, auf das reagiert werden soll (z. B. Mausklick)
     469* Das Oberflächenelement, für das das Ereignis überwacht werden soll (das Event-Target)
     470* Der Eventhandler, eine Funktion, die nach dem Eintritt des Ereignisses ausgeführt wird
     471
     472Das Prinzip nennt man ereignisgesteuerte Programmierung. Es ist die konzeptionelle Grundlage nahezu aller interaktiven Programme mit grafischer Benutzeroberfläche. Später werden wir sehen, dass nicht nur Benutzeraktionen Ereignisse auslösen können, die durch Eventhandler behandelt werden. Weitere Beispiele sind Netzwerkverbindungen: Wenn Anfragen (Requests) über das Netzwerk abgesendet werden, wartet das Programm meist nicht auf die Serverantwort, sondern registriert einen Handler, der aufgerufen wird, sobald die Antwort des Servers eintrifft (sog. Callback).
     473
     474Das vollständige Beispiel finden Sie in [[source:Web_Quellcode_FP/vorlesung/javascript/eventhandler.html|eventhandler.html]].
     475
     476Registrierung des Eventhandlers HTML-Element über das Attribut on''eventname'' (hier onclick):
     477
     478{{{
     479#!htm
     480...
     481<div id="d1" onclick="var s='Hallo';alert(s);">Ausgabe Hallo direkt</div>
     482
     483<div id="d2" onclick="clickD2();">Ausgabe Hallo Funktion</div>
     484
     485<script>
     486function clickD2() {
     487  var s="Hallo";
     488  alert(s);
     489}
     490</script>
     491}}}
     492
     493Im 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.
     494
     495Registrierung mittels DOM-Manipulation über die Funktion `addEventListener`:
     496
     497{{{
     498#!htm
     499...
     500<div id="d3">Message über benannten Eventhandler</div>
     501
     502<div id="d4">Message über anonyme Funktion</div>
     503
     504<script>
     505document.getElementById("d3").addEventListener("click", clickD2);
     506
     507document.getElementById("d4").addEventListener("click", function(){
     508    var s = "Hallo";
     509    alert(s);
     510});
     511</script>
     512}}}
     513
     514Im 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.
     515
     516Im 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.
     517
     518Falls die beim Registrieren eingebundene Funktion selbst kein Eventhandler ist, sondern einen zurückliefert, kann natürlich auch ein Funktionsaufruf erfolgen:
     519
     520{{{
     521#!javascript
     522function clickD3() {
     523    alert("Aufruf clickD3");
     524    return function() {
     525        alert("generierter Eventhandler");
     526    };
     527}
     528}}}
     529
     530Die Registrierung erfolgt dann mit dem Handler, der vom Funktionsaufruf `clickD3()` zurückgeliefert wird (beachte die runden Klammern hinter clickD3):
     531
     532{{{
     533#!javascript
     534document.getElementById("d3").addEventListener("click", clickD3());
     535}}}
     536
     537Der 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:
     538
     539{{{
     540#!javascript
     541document.addEventListener("click", function(e){
     542    alert("x: " + e.clientX + " / y: " + e.clientY);
     543});
     544}}}
     545
     546Events lassen sich also auch direkt mit dem gesamten Dokument als Event Target registrieren, nicht nur für einzelne HTML-Elemente.
     547
     548Es 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.
     549
     550== JSON - !JavaScript Object Notation ==
     551
     552JSON 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.
     553
     554Eine JSON-Zeichenkette lässt sich aus einem Objekt mittels JSON.stringify() erzeugen:
     555
     556{{{
     557#!javascript
     558> var bm = {name: "Bohrmaschine", preis: 73.99}
     559> bm
     560Object {name: "Bohrmaschine", preis: 73.99}
     561
     562> var json = JSON.stringify(bm)
     563> json
     564"{"name":"bohrmaschine","preis":73.99}"
     565}}}
     566
     567Mit der Funktion JSON.parse() lässt sich auf dem umgekehrten Weg ein !JavaScript-Objekt aus der JSON-Zeichenkette erezugen:
     568
     569{{{
     570#!javascript
     571> var bm2 = JSON.parse(json)
     572> bm2
     573Object {name: "Bohrmaschine", preis: 73.99}
     574}}}
     575
     576JSON-Zeichenketten enthalten nur die datenartigen Attribute der Objekte. Funktionsattribute werden nicht in die Zeichenkette kodiert:
     577
     578{{{
     579#!javascript
     580> bm.toString = function() {console.log(this.name + " " + this.preis);}
     581> bm.toString()
     582bohrmaschine 73.99
     583
     584> var json = JSON.stringify(bm)
     585> json
     586"{"name":"bohrmaschine","preis":73.99}"
     587
     588> var bm2 = JSON.parse(json)
     589> bm2.toString()
     590"[object Object]"
     591}}}
     592
     593Die Funktion `toString` ist in der JSON-Zeichenkette nicht enthalten. Statt dessen wird die geerbte Funktion `toString` des Objekts Object ausgeführt.
     594
     595Attribute, die selbst Objekte sind, und Arrays werden rekursiv in die JSON-Zeichenkette eingebaut:
     596
     597{{{
     598#!javascript
     599> var ww = {name: "Wasserwaage", preis: 25.00}
     600> var bestellung = {datum: "21.05.2017", kunde: "Susi Sonne", artikel: [bm, ww]}
     601> bestellung
     602Object {datum: "21.05.2017", kunde: "Susi Sonne", artikel: Array(2)}
     603
     604> var json = JSON.stringify(bestellung)
     605> json
     606"{"datum":"21.05.2017","kunde":"Susi Sonne","artikel":[{"name":"bohrmaschine","preis":73.99},{"name":"Wasserwaage","preis":25}]}"
     607}}}
     608
     609=== Workaround für nicht eingebundene Funktionen ===
     610Falls 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:
     611
     612{{{
     613#!CodeExample
     614## title = JSON Beispiel
     615## repo = Web_Quellcode_FP
     616## path = /vorlesung/javascript/json.html
     617#!html
     618}}}
     619
     620Die 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.
     621
     622Beispiel 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):
     623
     624{{{
     625#!javascript
     626> var bm = new Artikel("Bohrmaschine", 73.99)
     627> bm.toString()
     628"Bohrmaschine 73.99"
     629
     630> var ww = new Artikel("Wasserwaage", 25)
     631> ww.toString()
     632"Wasserwaage 25"
     633
     634> var b = new Bestellung("21.05.2017", "Willi Wacker")
     635> b.addArtikel(bm)
     636> b.addArtikel(ww)
     637> b
     638Bestellung {datum: "21.05.2017", kunde: "Willi Wacker", artikel: Array(2), addArtikel: function}
     639
     640> var js = JSON.stringify(b)
     641> js
     642"{"datum":"21.05.2017","kunde":"Willi Wacker","artikel":[{"name":"Bohrmaschine","preis":73.99},{"name":"Wasserwaage","preis":25}]}"
     643
     644> var b2 = JSON.parse(js)
     645> b2
     646Object {datum: "21.05.2017", kunde: "Willi Wacker", artikel: Array(2)}
     647}}}
     648
     649Das aus der JSON-Zeichenkette neu erstellte Objekt enthält keine Funktionen. Der Aufruf von `addArtikel` schlägt fehl:
     650
     651{{{
     652#!javascript
     653> b2.addArtikel(ww)
     654VM203:1 Uncaught TypeError: b2.addArtikel is not a function
     655    at <anonymous>:1:4
     656(anonymous) @ VM203:1
     657}}}
     658
     659Werden dagegen über `Bestellung.createFromJSON()` die ursprünglichen Konstruktorfunktionen verwendet, sind auch die Funktionen vorhanden und können aufgerufen werden:
     660
     661{{{
     662#!javascript
     663> var b2 = Bestellung.createFromJSON(js)
     664> b2.addArtikel(ww)
     665> b2
     666Bestellung {datum: "21.05.2017", kunde: "Willi Wacker", artikel: Array(3), addArtikel: function}
     667}}}
     668
     669== DOM Manipulation mit jQuery ==
     670
     671[[https://jquery.com|jQuery]] ist ein !JavaScript-Framework, das die DOM-Manipulation, insbesondere die Änderung von Darstellungseigenschaften der Oberflächenelemente stark vereinfacht.
     672
     673Mit 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]]:
     674
     675{{{
     676#!htm
     677<style>
     678.rot {color: red;}
     679.gruen {color: green;}
     680.blau {color: blue;}
     681</style>
     682
     683...
     684
     685<div id="d1">Bohrmaschine</div>
     686<div id="d2">Binford Tools</div>
     687<div id="d3">73.99</div>
     688
     689<p id="p1">Wasserwaage</p>
     690<p id="p2">Wasserversorgung Kamp-Lintfort</p>
     691<p id="p3">25.00</p>
     692}}}
     693
     694Die 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:
     695
     696{{{
     697#!javascript
     698> $("#d1")
     699[div#d1]
     700
     701> $("div")
     702(3) [div#d1, div#d2, div#d3, prevObject: jQuery.fn.init(1)]
     703}}}
     704
     705Auf den Ergebnissen lassen sich direkt weitere Aktionen zur DOM-Manipulation ausführen:
     706
     707{{{
     708#!javascript
     709> $("#d1").addClass("rot");
     710[div#d1.rot]
     711
     712> $("div").addClass("gruen");
     713(3) [div#d1.rot.gruen, div#d2.gruen, div#d3.gruen, prevObject: jQuery.fn.init(1)]
     714}}}
     715
     716Neue Elemente lassen sich mit `append`in das DOM einfügen:
     717
     718{{{
     719#!javascript
     720> $("#p3").append("<span>Ich bin neu hier</span>")
     721[p#p3]
     722
     723> $("#p3 span")
     724[span, prevObject: jQuery.fn.init(1)]
     725
     726> $("#p3 span").attr("id", "s1")
     727[span#s1, prevObject: jQuery.fn.init(1)]
     728
     729> $("#s1").addClass("blau")
     730[span#s1.blau]
     731}}}