JS

JavaScript

JS - Mindmap

JS - JavaScript

Dynamisch typisierte Skriptsprache zur clientseitigen Programmierung von Webanwendungen

JS - Ruf

Javascript and python are weirdos

Quelle: r/ProgrammerHumor

JS - Ruf

Javascript the good parts

Quelle: r/ProgrammerHumor

Historie - Steinzeit

  • 1995 (September): LiveScript als Beta in Netscape veröffentlicht (erster graphischer Web-Browser)
  • 1995 (Dezember): JavaScript offiziell in Netscape
  • 1996 (August): JScript im InternetExplorer
  • Netscape gibt JavaScript an "Ecma International" zur Standardisierung (ECMAScript 1)
  • Beginn des Browserkriegs

Historie - Bronzezeit

  • Microsoft gewinnt den Browserkrieg:
    95% Marktanteil in 2004 [0]
  • 2004: Mozilla veröffentlicht Firefox und gewinnt Marktanteile zurück von Microsoft IE
  • Versuche ECMAScript 4 zu standardisieren scheiterten
  • ab 2005: Open-Source Bibliotheken beleben JavaScript wieder: Ajax (2005) und jQuery (2006)
  • 2008: Google veröffentlicht Chrome
  • 2009 (Dezember): ECMAScript 5 veröffentlicht, Browserkrieg beendet

Historie - Neuzeit

  • 2009: Ryan Dahl veröffentlicht NodeJS: alleinstehende JavaScript-Umgebung
  • 2015: ECMAScript 6 mit (sehr) vielen neuen Features veröffentlicht: modernes JavaScript
  • 2016: Umstellung auf jährliche Releases
  • 2018: Npm ist die größte Sammlung an Modulen überhaupt
  • das Web hat sich als Platform gegen bestehende native Platformen (Mobile, PC) etabliert

JS - Hello World

						
					
./code-examples/1_hello-world/hello-world.js

Javascript einbinden

  • Methode 1: Event-Handler-Attribut
    <button onclick="meineFunktion('p');"></button>
    • im globalen Kontext
  • Methode 2: Script-Tag
    <script type="text/javascript">Mein Code</script>
    • Zentrale Stelle für JS-Code
  • Methode 3: JS-Datei
    <script type="text/javascript" src="MeinCode.js"></script>
    • Seitenübergreifend möglich
  • Methode 4: Debugger-Console (REPL, im Kontext)

JS - Anwendungsszenarien

  • Validierung bzw. Plausibilisieren von Formulardaten
  • Rückfragen (Dialogfenster)
  • Vorschlagen von Eingabewerten
  • Dynamisches Verändern von Webseiten
  • Senden und Empfangen von Daten ohne neues Laden der Seite (AJAX)

JS - Eigenschaften

  • Skriptsprache: keine Kompilierung, Code wird zur Laufzeit interpretiert
  • Dynamisch Typisiert:
    "Typ nach aktueller Verwendung"
  • Multi-Paradigma: objektorientiertes und funktionales Programmieren
  • Ein einziges Root-Objekt (im Browser: window)
  • Ein einziger Ausführungskontext (im Browser: Fenster/Tab)
  • Sandbox: Websiten haben keinen direkten Systemzugriff

JS - Sandbox

  • Browser kappselt JavaScript vom System ab
    Ausbrechen kann viel Geld bringen: z.B. 60k€
  • Kein Zugriff auf Inhalte anderer Webseiten:
    "same-origin-policy"
  • Zugriffe auf das System (z.B. Dateien, Webcam, Mikro) nur über definierte Schnittstellen

ABER: keine Abkappselung von eingebundener Dritt-Software (z.B. Werbebanner, Like-Button)

Datentypen und Variablen

						
					

Typ der Variable ergibt sich aus dem Ergebnis des Ausdrucks

Ohne Schlüsselwort: Kontext-Globale Variable

Datentypen und Variablen

						
					

Mit let/const Schlüsselwort: Block-Scope Variable

Mit var Schlüsselwort: Function-Scope Variable

Operatoren

  • +, -, *, /, %, ++ (Post- und Präfix), -- (Post- und Präfix)
  • +=, -=, *=, /=, %=
  • && (und), || (oder), ! (Negation),
    ==, ===, !=, !==, <, >, <=, >=
  • Bit-Operatoren: <<, >>, &, |, ^, ~ (Bit-Negation)
  • + (Verketten von Zeichenketten)

Automatische Typumwandlung

console.log("47" + 11); // "4711"
console.log("47" * 1 + 11); // 58

Die Typumwandlung kann sehr "unerwartete" Ausmaße annehmen: WAT

Gleichheit und Typumwandlung

Automatische Typumwandlung für Bestimmung der Gleichheit

console.log("42" == 42); // true

Ohne automatische Typumwandlung

console.log("42" === "42"); // true
console.log("42" === 42); // false

console.log("42" !== "42"); // false
console.log("42" !== 42); // true

Zeichenketten

Verketten mit "+" Operator

console.log("Hello" + " " + "World"); // Hello World

Länge einer Zeichenkette

const s = "Hello World";
console.log(s.length); // 11

Zeichen Nummer x aus Zeichenkette s

const s = "Hello World";
console.log(s.chart(0)); // H
console.log(s[1]); // e

MDN: String

Kommentare & Anweisungen

Ein- oder mehrzeilen Kommentare

// Hello World
/* Hello
   World */

Anweisungen müssen nicht mit ";" beendet werden

console.log("Hello")
console.log("World");

Anweisungsblöcke werden mit geschweiften Klammern gebildet {}

Schleifen

for-Schleifen

for (Initialisierung; Bedingung; Befehlsfolge) {
    // Anweisungen
}

for (e in collection) {
    // Anweisungen
}

do-while-Schleifen

do {
    // Anweisungen
} while (Bedingung)

while (Bedingung) {
    // Anweisungen
}

Schleifensteuerung

  • break
    Vorzeitiges Verlassen einer Schleife
  • continue
    Vorzeitiges Beenden eines Schleifendurchgangs

Fallunterscheidungen

if (Bedingung){ 
	//Anweisungsblock 
} else if (Bedingung) { 
	//Anweisungsblock 
} else { 
	//Anweisungsblock 
}

switch (Ausdruck){ 
	case Wert1: 
		//Programmblock 
		break 
	case Wert2: 
		//Programmblock 
		break 
	default: 
		//Programmblock 
}

Arrays

Deklaration (mit Initialisierung)

let a = new Array();
let b = new Array(5);
let c = [];

let d = new Array("eins", "zwei", "drei");
let e = [1, 2, 3, 4]

Länge

console.log(a.length) // 0
console.log(b.length) // 5

Zugriff

a[4] = "Hello World";
let s = a[4];

Funktionen

Deklaration

function Funktionsname(Parameter1, Parameter2) {
	// Programmblock;
	return Wert;
}

Anzahl der Parameter beim Aufruf ist beliebig!
Ungesetzte Parameter sind "undefined"

Ohne oder leeres return ergibt implizit "undefined"

Funktionsaufrufe

function f(Parameter1, Parameter2) {
	console.log(Parameter1);
	console.log(Parameter2);
	return Parameter1;
}
f("eins", "zwei");
// eins
// zwei
// return: "eins"
f("drei");
// drei
// undefined
// return: "drei"

Funktionen

Deklaration einer Funktion muss

  • im gleichen Script-Block
  • in einem textuell vorherigen Script-Block

erfolgen.

Funktionsparameter

  • Aufruf mit zu weniger Parametern
    • Werte werden auf undefined gesetzt
  • Aufruf mit zu vielen Parametern
    • Funktionen sind Objekte mit Attribut "arguments"
    • Zugriff via <Funktionsname>.arguments

Hilfskonstrukt!
Geht sehr schnell auf die Les- und Wartbarkeit

Funktion.arguments

function g() {
	console.log(g.arguments[0]);
	console.log(g.arguments[1]);
}
g(1, 2);
// 1
// 2
g("drei");
// drei
// undefined

Funktionen und Variablen

let a = 0;
let b = 0;
function test() {
	a++; // Zugriff auf Variable a
	console.log(a);
	let b = 1; // Neue(!) lokale Variable
	console.log(b);
}
test();
// 1
// 1
console.log(b); // 0

Ohne Schlüsselwort wird eine globale Variable erstellt bzw. überschrieben!

"Window trashing" -> schlechter Stil

Objekte - Konstruktor

function Calculator(x, y) { // Deklaration
	this.x = x;
	this.y = y;
	this.sum = function sum() {
		return this.x + this.y;
	}
}
const c = new Calculator(4,3); // Instanziierung
c.sum(); // 7, Methodenaufruf

Objekte sind zur Laufzeit erweiterbar

const c = new Calculator(4,3); // Instanziierung
c.diff = function diff() {
	return this.x - this.y;
};
c.diff() // 1, Methodenaufruf

Objekte - Zuweisung

const c = { // Instanziierung
	x: 4,
	y: 3,
	sum: function() {
		return this.x + this.y;
	}
}
c.sum(); // 7, Methodenaufruf

Objekte & Funktionen

function Position(x,y) {
	this.x = x;
	this.y = y;
	return "(" + x + "," + y + ")"
}

a = Position(3,4); // "(3,4)"

a = new Position(3,4); // Objekt mit x=3 und y=4

this

Bezugspunkt fuer den Aufrufer/Kontext

Bisher: die aktuelle Objekt-Instanz

function whatTheThis() {
	return this.a;
}

a = 16;
console.log(a); // 16
console.log(window.a); //16

console.log(whatTheThis()); // 16
console.log(window.whatTheThis()); // 16

this

Außerhalb aller Anweisungsblöcke (global execution context) zeigt es auf das root-Objekt,
im Browser: window

Modernes JavaScript: "globalThis" verweisst immer auf das root-Objekt

Standardobjekte (Browser-APIs)

  • window (MDN)
    • root-Objekt und Browserfenster
      innerHeight, innerWidth
  • document (MDN)
    • HTML Dokument: cookie, title
  • Date (MDN)
    • Datumsverarbeitung
      new Date() -> aktuelles Datum
  • freie Funktionen (MDN)
    • kleine Helfer

Standardfunktionen (Auswahl)

  • alert(message)
    • Ausgabe einer Nachricht in einem modalen Fenster
  • encode(uri) / decode(uri)
    • Enkodieren und dekodieren von URIs
  • isFinite(zahl) / isNaN(zahl)
    • Prüfen auf Wertbereich
  • parseFloat(string) / parseInt(string)
    • Typwandlung

Document Object Model (DOM)

Representation des HTML-Dokuments im Speicher

Datenstruktur: Baum (Tree Powers Activate!)

Schnittstelle zwischen
JavaScript und HTML-Dokument

Einstiegsschnittstelle: document

Zugriff auf Dokument

Suchen eines Elements

	// Modern: CSS-Selektor
// Findet erstes 'h1'-Element, <-Objekt
document.querySelector("h1");
// Findet alle 'h1'-Elemente, <-Array
document.querySelectorAll("h1");

// Klassisch: einzelne Methoden
// Findet Element mit id='id', <-Objekt
document.getElementById("id");
// Findet alle Elemente mit name='name', <-Array
document.getElementsByName("name");
// Findet alle 'h1'-Elemente, <-Array
document.getElementsByTagName("h1");
// ...

Zugriff auf Dokument

Erzeugen eines neuen Elements

	// Erzeugt neues "div"-Element, <-Objekt
document.createElement("div");
// Erzeugt neuen Textinhalt, <-Objekt
document.createTextNode("Lorem ipsum");

Passiert alles im Speicher! Erst Sichtbar wenn es dem "body" hinzugefügt wird!

Zugriff auf Dokument

Manipulieren des Dokuments

	// Hängt ein Element als Kind eines anderen in den Baum
element.appendChild(element);
// !Wirft HierarchyRequestError (DOMException)
// z.b. wenn ein Zyklus entstehen würde

// Objekte erstellen
const newDiv = document.createElement("div");
const newContent = document.createTextNode("text!");

// Füge den Inhalt dem Div hinzu
newDiv.appendChild(newContent);

// Füge den neuen Div dem Body hinzu
document.body.appendChild(newDiv);

Zugriff auf Dokument

Manipulieren des Dokuments

	// Ersetzt ein Element durch ein anderes
element.replaceChild(newElement, oldElement);
// Entfernt ein Element
element.replaceChild(oldElement);

// Liest Attribut eines Elements aus
element.getAttribute("name");
// Setzt ein Attribut des Elements
element.setAttribute("name", "value");

Zugriff auf Dokument

Navigation durch das Dokument

	// Zeiger auf Kind-Elemente
element.firstElementChild; element.lastElementChild;
// Zeiger auf "Beziehungs"-Elemente
element.nextElementSibling; element.previousElementSibling;
node.parentNode;

Zugriff auf Dokument

Element/Knoten-Attribute

	// Textinhalt - komplett
node.textContent;
// Textinhalt:
//  - human-readable: kein script, style
//  - style-aware: kein Text von "hidden" Elements
element.innerText;

// HTML-Inhalt
element.innerHTML;
// !Wirft SyntaxError (DOMException)
// wenn zugewiesener Wert kein gültiges HTML ist

// Style
element.style;
// Setze Schriftfarbe
element.style.color = 'red';
// Standardfarbe wiederherstellen
element.style.color = null;

Event-Handler

  • Event-Attribute
    • onclick, ondblclick
    • onkeydown, onkeyup, onkeypress
    • onmousedown, onmouseup, onmouseover
    • ...

Beispiel: <p onclick="alert('click')">Hallo!</p>

Add Event-Handler

	element.addEventListener(event, listener, options)//new(er)
element.addEventListener(event, listener, useCapture)//old(er)
  • addEventListener (MDN)
    • event: Name des Events (ohne "on")
    • listener: Aufzurufende Funktion
    • options (Optional): Objekt mit Optionen
      • capture: siehe useCapture (default: false)
      • once: nur einmal Aufrufen (default: false)
    • useCapture (Optional): boolean
      • true: Aufruf zuerst auf Elternelement
      • false: Event-Bubbles (default)

Remove Event-Handler

	element.removeEventListener(event, listener, options)
element.removeEventListener(event, listener, useCapture)
  • removeEventListener (MDN)
    • event: Name des Events (ohne "on")
    • listener: Aufzurufende Funktion
    • options (Optional): Objekt mit Optionen
      • capture: siehe useCapture (default: false)
    • useCapture (Optional): boolean
      • true: Aufruf zuerst auf Elternelement
      • false: Event-Bubbles (default)

Event-Handler Parameter

	const listener = function(event /* MouseEvent */) {
	console.log(event.clientX + " / " + event.clientY);
};
element.addEventListener("click", listener);
  • event (MDN)
    • target: Auslösendes Element
    • type: Art des Events
    • stopPropagation(): bursts the bubble
  • Unterklassen
    • Mouse-Event (MDN), z.B. ctrlKey, altKey, shiftKey
    • Keyboard-Event (MDN), z.B. key,
      code (ohne Tastaturlayout)

Event-Handler Parameter

Übergeben von weiteren Parametern?

	const listener = function(event, p1, p2) {
	console.log(p1 + "; " + p2);
};
element.addEventListener("click", function(event) {
	listener(event, p1, p2);
});

oder via Handlerzuweisung per Attribut

	<p onclick="listener(event, p1, p2);">...</p>

Zugriff auf Formulardaten

	// indiziert
document.forms[3].elements[4].value

// assoziativ via names
document.forms.myForm.elements.x.value

// assoziativ verkürzt
document.myForm.x.value

Empfehlung: Eindeutige Namen für Formulare (und Eingabeelemente) vergeben!

Empfehlung: Zugriffsformen nicht mischen!!
(Les- und Wartbarkeit)

Praxis - Javascript - Aufgabe 1

let a = 1;
b = 5;
let c = new Array("eins", "zwei", "drei");
function test(e, f) {
	for(g in c) {
		let b = e + a;
		a = a + 1;
	}
	c = [f];
}
console.log("a='" + a + "' b='" + b + "' c='" + c + "'");
test(4,5);
console.log("a='" + a + "' b='" + b + "' c='" + c + "'");
test(6,7);
console.log("a='" + a + "' b='" + b + "' c='" + c + "'");

Welchen Wert haben die Variablen a,b,c vor und nach den "test"-Aufrufen? Welche Strings geben die "console.log" aus?

Praxis - JavaScript - Aufgabe 2

  • Erstellen Sie ein statisches Adress-Formular:
    Name, Vorname, Straße, Hausnummer, Plz, Ort
  • Gebt nach jeder Änderung unterhalb des Formulars die eingegebenen Daten in Form eines "Adressaufklebers" aus.
  • Ein Klick auf einen Bereich des Addressaufklebers soll den Eingabe-Fokus auf das zugehörige Eingabefeld setzen.

Praxis - JavaScript - Aufgabe 3

  • Erstellen Sie eine Flexbox/Grid, die als erste Spalte eine Auswahlspalte mit Checkboxen enthält, danach eine Spalte mit einem Superhelden.
  • Initial ist der Knopf "Starte Mission" ausgeschaltet.
  • Ist mehr als eine Checkbox gewählt wird der Knopf eingeschaltet.
  • Gebt die Anzahl eingeschalteter Checkboxen neben dem Button aus.

JS - Lösungen Aufgabe 1

a='1' b='5' c='eins,zwei,drei'
a='4' b='5' c='5'
a='5' b='5' c='7'

AJAX - Asynchronous JavaScript and XML

Asynchrone Datenübertragung zwischen
Browser und Server

Daten zum Browser übertragen außerhalb von Seiten-Navigationen

Aufruf des Servers, Empfangen und Verarbeiten der Antwort durch JavaScript

Daten müssen nicht(!) im XML-Format sein

AJAX vs. Seitenabruf

Seitenabruf

  1. Browser stellt Seite1.html dar
  2. Browser sendet Request
  3. Server schickt HTML-Seite
    an Browser
  4. Browser stellt neue
    HTML-Seite dar

AJAX vs. Seitenabruf

AJAX

  1. Browser stellt Seite1.html dar
  2. Browser sendet AJAX-Request
  3. Server schickt JSON-Daten
    an Browser
  4. JavaScript verarbeitet Daten und stellt sie auf Seite1.html dar

Einsatzszenarien

  • Eingabehilfen
    • Vorschlagen während des Tippens
    • Autovervollständigung (z.B. PLZ -> Ort)
  • Nachladen von Daten
    • Indikatoren das neue Daten verfügbar sind
    • Scrollen durch endlose Listen
  • Neue Bedienkonzepte
    • Browserspiele
  • Reine JavaScript-Clients
    • Office 360

Vor- und Nachteile

Vorteile

  • schneller: nur Daten übertragen
  • sanfter: Bildschirm aktualisiert weicher
  • dynamischer: ermöglicht weitere Interaktionskonzepte

Nachteile

  • Im Allgemeinen nicht Barrierefrei
  • Widerspruch zur Browsernavigation(Vor-/Zurück-Button, Bookmarks, ...)
  • Schwierig für Suchmaschinen

APIs

API-Stile, Protokolle

  • SOAP - Simple Object Access Protocol
    • XML-basiertes Protokoll für Webservices
    • Transport über HTTP POST
  • REST - Representational State Transfer
    • Architektur-Stil um "internet-scale" zu erreichen
    • Nutzt standard HTTP-Methoden (GET, POST, PUT, DELETE) mit Parametern
    • Oftmals JSON als Datenformat

JSON vs. XML

https://api.github.com/users/chr1shaefn3r

{
	"login": "chr1shaefn3r",
	"id": 11996484,
	"node_id": "MDQ6VXNlcjExOTk2NDg0",
	"avatar_url": "https://avatars.githubusercontent.com/u/11996484?v=4",
	"type": "User",
	"name": "Christoph Häfner"
}

	chr1shaefn3r
	https://avatars.githubusercontent.com/u/11996484?v=4
	Christoph Häfner

XMLHTTPRequest

  • API zum Transfer von beliebigen Daten über HTTP
  • Old-school JavaScript API (MDN)
  • Event-basierte API
  • Unterschiede zwischen den Browsern vorhanden (versionsabhängig!)
  • Spec: https://xhr.spec.whatwg.org/

XMLHTTPRequest - Methoden

Herstellen einer Verbindung (MDN)

	const request = new XMLHttpRequest();
request.open(method, url[, async=true[, user=null[, password=null]]])

Anfrage senden (MDN)

request.send([body=null])
  • Verbindung muss geöffnet sein!
  • Verschiedene Datentypen möglich, z.B. String, Array, Blob (Binärdaten)

XMLHTTPRequest - Events

  • Event-Handler
    • readystatechange
    • load, error, progress
  • Status für Anfragen: readyState
    • 0: Objekt wurde erzeugt
    • 1: Open() wurde aufgerufen
    • 2: HTTP-Header empfangen
    • 3: Empfangen
    • 4: Anfrage abgeschlossen

Daten der Antwort: responseText, responseXML

XMLHTTPRequest - Beispiel

						// XMLHTTPRequest erzeugen
const request = new XMLHttpRequest();

// Event-Handler um Antwort auszugeben
function reqListener () {
	console.log(this.responseText);
}

// Event-Handler für Antwort setzen
request.addEventListener("load", reqListener);

// Verbindung öffnen
request.open("GET", "https://api.github.com/users/chr1shaefn3r");

// Anfrage abschicken
request.send();

XMLHTTPRequest - Beispiel2

						// XMLHTTPRequest erzeugen
const request = new XMLHttpRequest();

// Event-Handler für Antwort setzen
request.onreadystatechange = function receive() {
	if(request.readyState==4) {
		console.log(request.responseText);
	}
}

// Verbindung öffnen
request.open("GET", "https://api.github.com/users/chr1shaefn3r");

// Anfrage abschicken
request.send();

fetch

  • alternative zu XMLHTTPRequest
  • Moderne JavaScript API (MDN)
  • Ist auch in einem "WebWorker" verfügbar
  • Ist nicht im "Internet Explorer" verfügbar
  • Promise-basierte API
  • Spec: https://fetch.spec.whatwg.org/

fetch - Aufruf

						const responsePromise = fetch(resource, [, init])
  • resource: Aufzurufende URL
  • init: Objekt mit optionalen Parametern (headers, credentials, redirect, ...)
  • return: Promise (MDN), das auf die Antwort wartet
    • then(handleResolve, handleReject)
    • catch(handleCatch)
    • finally(handleFinally)
    • Handler bekommen ein Response-Objekt übergeben

fetch - Response Objekt

Rückgabewert der Fetch-API (MDN)

  • status: Status Code des Aufrufs
  • statusText: Text des Status
  • ok: Anfrage war Erfolgreich (status 200-299)
  • text(), json(), formData(), blob():
    Inhalt der Antwort in Form eines Promise

fetch - Beispiel

						fetch(
	"https://api.github.com/users/chr1shaefn3r"
).then(
	function(response) {
		response.json().then(
			function(githubUser) {
				console.log(githubUser);
			}
		);
	}
);
	fetch("https://api.github.com/users/chr1shaefn3r")
.then((response) => response.json())
.then((githubUser) => console.log(githubUser));

JSON - Javascript Object Notation

  • Datenaustauschformat
    • Kommunikation eines Servers mit einem JavaScript-Client
  • Kompaktere Darstellung als XML
  • Native Unterstützung in JavaScript
    • JSON.parse: String zu JavaScript-Objekt
    • JSON.stringify: JavaScript-Objekt zu String

JSON - Beispiel

https://api.github.com/users/chr1shaefn3r

{
	"login": "chr1shaefn3r",
	"id": 11996484,
	"node_id": "MDQ6VXNlcjExOTk2NDg0",
	"avatar_url": "https://avatars.githubusercontent.com/u/11996484?v=4",
	"type": "User",
	"site_admin": false,
	"name": "Christoph Häfner",
	"hireable": null,
	"bio": null,
	"public_repos": 5,
}

JSON - Datentypen

  • Objekte - {"Schüssel1": wert, "Schlüssel": wert2, ...}
  • Nullwert - null
  • Boolesche Werte - true, false
  • Zahlen
  • Zeichenkette - begrenzt durch ""
  • Array - [wert1, wert2, ...]
  • Leerzeichen/Neuzeilen sind erlaubt
  • KEINE: Funktionen, Prototypen,
    zirkuläre Referenzen

JSON - Auslesen

JSON.parse

						const myObject = JSON.parse('{"label": "Hello World"}');
console.log(myObject.label); // "Hello World"

const myObject = JSON.parse(
	'{"label": function() { return "Hello World" }'
);
// Uncaught SyntaxError: Unexpected token [...]

JSON - Einlesen

JSON.stringify

	const myObject = {"label": "Hello World"};
console.log(JSON.stringify(myObject));
// '{"label":"Hello World"}'

JSON.stringify(objectWithCircularReference);
//Uncaught TypeError: Converting circular structure to JSON

JSON - (Anti)Pattern

Tiefes Klonen eines JavaScript-Objekts

						const mutate = function(o) {
	o.a = 4;
}

const myObject = { a: 2 };
mutate(myObject);
console.log(myObject.a); // 4

const myObject = { a: 2 };
mutate(JSON.parse(JSON.stringify(myObject)));
console.log(myObject.a); // 2

Moderne alternative: structuredClone() (MDN)
Kann auch mit zyklischen Abhängigkeiten umgehen

fetch()+JSON - Beispiel

Website/HTML:

						<body>
	<h1>Fetch Beispiel</h1>
	<p>x = <span id="x"></span></p>
	<p>t = <span id="t"></span></p>
	<p>
		<input type="button" value="load" onclick="loadData()">
	</p>
</body>

JSON API-Antwort:

	{ "x": 5, "t": "hello World" }

fetch()+JSON - Beispiel

JS-Script:

						function loadData () {
	fetch(url)
	.then(response => response.json())
	.then(function(data) {
		document.getElementById("x").innerText = data.x;
		document.getElementById("t").innerText = data.t;
	});
}

Arrow-Functions

Old-School JavaScript:
function und this-Kontext wird vom Aufrufer gesetzt
Überraschender this-Kontext, verkompliziert Einstieg in JavaScript

Modernes JavaScript:
=> und this-Kontext des Scopes
Leichter verständlich, weniger Workarounds

Functions and this (again)

this ist nicht was man erwarten würde

						function GithubUser(name) {
	this.name = name
};

GithubUser.prototype.download = function() {
	console.log(this.name);
	fetch("https://api.github.com/users/" + this.name)
	.then(function(data) {
		console.log(this.name);
	});
}

new GithubUser("chr1shaefn3r").download();
// "chr1shaefn3r" (Zeile 6)
// undefined (Zeile 9)

Warum ist "this.name" in Zeile 6 + 9 nicht das gleiche? WTF?!?

Functions and this (again)

Workaround um an this ranzukommen

						function GithubUser(name) {
	this.name = name
};

GithubUser.prototype.download = function() {
	var that = this;
	fetch("https://api.github.com/users/" + that.name)
	.then(function(data) {
		console.log(that.name);
	});
}

new GithubUser("chr1shaefn3r").download();
// "chr1shaefn3r" (Zeile 9)

Arrow-Functions and this (again)

						function GithubUser(name) {
	this.name = name
};

GithubUser.prototype.download = function() {
	fetch("https://api.github.com/users/" + this.name)
	.then((data) => {
		console.log(this.name);
	});
}

new GithubUser("chr1shaefn3r").download();
// "chr1shaefn3r" (Zeile 8)

weniger Syntax zu tippen, richtiges Ergebnis, ganz ohne Workaround: great success!

Function vs. Block-Scope

Old-School JavaScript:
var und Function-Scope
Überraschende Variablengültigkeiten, verkompliziert Einstieg in JavaScript

Modernes JavaScript:
let/const und Block-Scope
Vergleichbarer mit bestehenden Konzepten aus anderen Programmiersprachen (Java, C++, Rust, etc.)

Function-Scope

						function whatTheFunctionScope(data) {
	for(var index = 0; index < data.length; index++) {
		/* do something with data[index] */
	}
	console.log(index);
};
whatTheFunctionScope(["wert"]); // 1

Warum ist die Variable "index" in Zeile 5 noch gültig?!? WTF?!?!

What the fuck per minute

Function-Scope (hoisting)

						function whatTheFunctionScope() {
	console.log(index);
	var index = 1;
	console.log(index);
};
whatTheFunctionScope();
// undefined
// 1

Warum ist die Variable "index" in Zeile 2 schon verfügbar?!? WTF?!?!

What the fuck per minute

Block-Scope

						function theBlockScope(data) {
	for(let index = 0; index < data.length; index++) {
		/* do something with data[index] */
	}
	console.log(index);
};
theBlockScope(["wert"]);
// Uncaught ReferenceError: index is not defined

Die Variable "index" ist auf den Block der for-Schleife beschränkt. So wie man es erwarten würde.

KEIN hoisting!

JavaScript Objektorientierung

Was bisher geschah:

  • new: "normale" Funktion als Konstruktor
  • Objektattribute (z.B. Position mit x und y)
  • Methoden (z.B. Calculator mit sum und diff)

Was noch fehlt:

  • Vererbung
  • Polymorphismus

Und woher kommt eigentlich dieses "toString"?:

						const myObject = { x: 4, y: 2};
console.log(myObject.toString()); // "[object Object]"

JavaScript Prototypes

  • Eingebautes Objektattribut genannt "prototype"
  • "prototype" ist selbst ein Objekt (rekursion!)
  • Lesende Objektzugriffe werden bei Bedarf an den Prototype weitergeleitet (rekursion!!)
  • Ende der Kette: Objekt mit "null" als Prototype (Rekursions-Ende)
  • Konzept: "Prototype chain" (MDN)
    Grundlage für Vererbung

JavaScript Prototypes

Prototyp erweitern

						const obj = { x: 4, y: 2};
obj.__proto__.d = 5; // __proto__ ist Implementierungsdetail
Object.getPrototypeOf(obj).d = 5; // ES5 Standard
console.log(obj.d); // 5

JavaScript Prototypes

Klassen-Prototype erweitern

	function Calculator(x, y) {
	this.x = x;
	this.y = y;
}

Calculator.prototype.sum = function() {
	return this.x + this.y;
}

const c = new Calculator(4, 2);
console.log(c.sum()); // 6

JavaScript Prototypes/Vererbung

	function Person(name) {
	this.name = name;
}
Person.prototype.vorstellen = function() {
	console.log("Hallo, mein Name ist " + this.name)
}

function Dozent(name, fach) {
	Person.call(this, name);
	this.fach = fach;
}

// Prototypen-Kette setzen "Vererbung"
Dozent.prototype = Person.prototype;

Dozent.prototype.bewerten = function (klausur) {
	if(klausur.fach === this.fach) { /* Impl */ }
}

new Dozent("Christoph", "WebEngineering1").vorstellen();
// "Hallo, mein Name ist Christoph"

Prototypes vs. classes

Prototypes

Iron Man Mark 1 - The Prototype

ES6: classes

Iron Man Mark 3 - Polished

ES6: Classes

	class Person {
	name;
	constructor(name) {
		this.name = name;
	}
	vorstellen() {
		console.log("Hallo, mein Name ist " + this.name)
	}
}
class Dozent extends Person {
	fach;
	constructor(name, fach) {
		super(name);
		this.fach = fach;
	}
	bewerten(klausur) {
		if(klausur.fach === this.fach) { /* Impl */ }
	}
}
new Dozent("Christoph", "WebEngineering1").vorstellen();
// "Hallo, mein Name ist Christoph"

Sonst noch so...

Typescript: Verbreitetste JS-Variation [0]
Erweitert JS-Syntax um Typsystem (Superset), kompiliert nach JavaScript

ASM.js -> WASM (WebAssembly)
Anstatt JS programmieren, Web-Plattform als "compile target", z.B. LibreOffice im Browser [1], [2]

Nach REST: GraphQL
Abfragesprache, mit einem Request aus vielen verschiedenen Resourcen genau die Attribute abfragen die im UI benötigt werden, z.B. Github-API v4

Praxis - JavaScript - Aufgabe 3

  • Erstellt eine Website mit einem kurzen Textabsatz eurer Wahl, einem Button mit Text "Rot", und einem Button mit Text "Blau"
  • Ein Klick auf den Button "Rot" soll die Schriftfarbe des Textabsatz auf "Rot" ändern
  • Ein Klick auf den Button "Blau" soll die Schriftfarbe des Textabsatz auf "Blau" ändern

HTML-Vorlage: website-aufgabe3.html

Praxis - fetch - Aufgabe 4

Github Profil Seite

  • Erstellt eine Website mit Textfeld und Button
  • Beim Klick des Buttons soll der Text aus dem Eingabefeld als Username interpretiert und an Github geschickt werden
  • Stellt das Ergebnis grafisch dar (samt Bild)
  • Optional: Fehlerseite wenn Username nicht existiert
  • Optional: Lade-Indikator

Github User REST-Api: "https://api.github.com/users/{username}"

Lösung - JavaScript - Aufgabe 3

loesung-aufgabe3.html