Webentwicklung & Agentic Coding
Sommersemester 2026
Jede Webseite besteht aus drei Technologien:
| Technologie | Aufgabe | Analogie |
|---|---|---|
| HTML | Struktur & Inhalt | Skelett / Rohbau |
| CSS | Darstellung & Layout | Farbe / Einrichtung |
| JavaScript | Verhalten & Interaktivität | Elektrik / Haustechnik |
JavaScript macht Webseiten lebendig:
JavaScript ist die einzige Programmiersprache, die nativ in jedem Browser läuft.
1. Inline im HTML (nicht empfohlen):
<button onclick="alert('Hallo!')">Klick</button>
2. Internes Script-Tag:
<script>
console.log('Hallo aus dem Script-Tag!');
</script>
3. Externes Skript (Best Practice):
<script src="skript.js" defer></script>
Das defer-Attribut:
defer: Browser stoppt HTML-Parsing, lädt und führt JS sofort ausdefer: JS wird geladen, aber erst nach dem HTML-Parsing ausgeführtdefer verwenden oder <script> am Ende von <body> platzierenDie Konsole ist Ihr wichtigstes Werkzeug zum Testen und Debuggen:
Öffnen: F12 → Tab „Console" (oder Strg+Umschalt+J)
// Ausgabe in der Konsole
console.log('Hallo Welt!');
console.log(42);
console.log('Name:', 'Schuchardt');
// Warnung und Fehler
console.warn('Achtung: Wert fehlt');
console.error('Fehler beim Laden');
// Objekte schön formatiert
console.table({name: 'Hugo', jahr: 1842});
Direkt in der Konsole tippen:
> 2 + 3
5
> 'Hugo' + ' ' + 'Schuchardt'
"Hugo Schuchardt"
> typeof 42
"number"
Tipp: Die Konsole ist ein Spielplatz — probieren Sie alles direkt aus!
Variablen sind benannte Speicherplätze für Werte:
// const = Konstante (Wert ändert sich nicht)
const name = 'Schuchardt';
const geburtsjahr = 1842;
const istLinguist = true;
// let = Variable (Wert kann sich ändern)
let briefZaehler = 0;
briefZaehler = briefZaehler + 1; // jetzt 1
briefZaehler = briefZaehler + 1; // jetzt 2
// FEHLER: const kann nicht neu zugewiesen werden
const stadt = 'Graz';
stadt = 'Wien'; // TypeError!
Wann was verwenden?
const: Standard-Wahl. Verwenden Sie const, wenn sich der Wert nicht ändern soll.let: Nur wenn sich der Wert im Programm ändern muss (Zähler, Status-Variablen).var: Veraltet — nicht mehr verwenden!Namenskonvention: camelCase — briefTitel, absenderName, empfangsJahr
JavaScript hat verschiedene primitive Datentypen:
// String — Text in Anführungszeichen
const titel = 'Brief an Otto Benndorf';
const stadt = "Graz";
// Number — Ganze Zahlen und Dezimalzahlen
const jahr = 1879;
const laenge = 3.5;
// Boolean — Wahrheitswert (true/false)
const istPubliziert = true;
const hatAntwort = false;
// Spezialwerte
const unbekannt = null; // bewusst leer
let nichtDefiniert; // undefined (kein Wert zugewiesen)
Typ herausfinden mit typeof:
console.log(typeof titel); // "string"
console.log(typeof jahr); // "number"
console.log(typeof istPubliziert); // "boolean"
console.log(typeof unbekannt); // "object" (JS-Bug!)
console.log(typeof nichtDefiniert); // "undefined"
Array — eine geordnete Liste von Werten:
const sprachen = ['Deutsch', 'Romanisch', 'Baskisch'];
console.log(sprachen[0]); // "Deutsch" (Index beginnt bei 0!)
console.log(sprachen.length); // 3
// Neues Element hinzufügen
sprachen.push('Kreolisch');
console.log(sprachen.length); // 4
Object — eine Sammlung von Schlüssel-Wert-Paaren:
const brief = {
titel: 'Brief an Karl Vossler',
absender: 'Hugo Schuchardt',
empfaenger: 'Karl Vossler',
jahr: 1904,
ort: 'Graz'
};
console.log(brief.titel); // "Brief an Karl Vossler"
console.log(brief['jahr']); // 1904
console.log(Object.keys(brief)); // ["titel","absender","empfaenger","jahr","ort"]
Arrays und Objects sind die wichtigsten Datenstrukturen in JavaScript!
Arithmetische Operatoren:
const summe = 1842 + 85; // 1927 (Todesjahr)
const diff = 1927 - 1842; // 85 (Lebensalter)
const produkt = 12 * 5; // 60
const quotient = 100 / 4; // 25
const rest = 17 % 5; // 2 (Modulo)
Vergleichsoperatoren:
console.log(5 === 5); // true (strikt gleich)
console.log(5 === '5'); // false (verschiedene Typen!)
console.log(5 !== 3); // true (strikt ungleich)
console.log(1879 > 1900); // false
console.log(1879 <= 1900); // true
Logische Operatoren:
const jahr = 1879;
console.log(jahr > 1800 && jahr < 1900); // true (UND)
console.log(jahr < 1800 || jahr > 1900); // false (ODER)
console.log(!(jahr === 1879)); // false (NICHT)
Immer === statt == verwenden! Strikter Vergleich prüft auch den Typ.
Template Literals verwenden Backticks (`) statt Anführungszeichen:
const name = 'Hugo Schuchardt';
const jahr = 1842;
const ort = 'Graz';
// Alte Methode: String-Verkettung mit +
const text1 = name + ', geboren ' + jahr + ' in ' + ort;
// Moderne Methode: Template Literals mit ${...}
const text2 = `${name}, geboren ${jahr} in ${ort}`;
// Beide ergeben: "Hugo Schuchardt, geboren 1842 in Graz"
Vorteile von Template Literals:
${...} einbetten`Alter: ${1927 - 1842} Jahre`\n:const html = `
<div class="brief">
<h2>${brief.titel}</h2>
<p>Von: ${brief.absender}</p>
</div>
`;
Template Literals sind besonders nützlich, wenn wir HTML-Code in JavaScript erzeugen!
Code nur ausführen, wenn eine Bedingung erfüllt ist:
const jahr = 1879;
if (jahr > 1880) {
console.log('Nach 1880 verfasst');
} else if (jahr === 1880) {
console.log('Genau 1880 verfasst');
} else {
console.log('Vor 1880 verfasst');
}
// Ausgabe: "Vor 1880 verfasst"
Praxisbeispiel — Brief-Kategorisierung:
const brief = { jahr: 1904, sprache: 'Deutsch', seiten: 3 };
if (brief.seiten > 5) {
console.log('Langer Brief');
} else if (brief.seiten > 2) {
console.log('Mittlerer Brief');
} else {
console.log('Kurzer Brief');
}
// Kombination mit logischen Operatoren
if (brief.jahr > 1900 && brief.sprache === 'Deutsch') {
console.log('Deutscher Brief aus dem 20. Jh.');
}
for-Schleife — klassisch mit Zähler:
const briefe = [
'Brief an Benndorf',
'Brief an Vossler',
'Brief an Meringer'
];
for (let i = 0; i < briefe.length; i++) {
console.log(`${i + 1}. ${briefe[i]}`);
}
// 1. Brief an Benndorf
// 2. Brief an Vossler
// 3. Brief an Meringer
for...of-Schleife — moderner und lesbarer:
for (const brief of briefe) {
console.log(brief);
}
// Brief an Benndorf
// Brief an Vossler
// Brief an Meringer
Wann was verwenden?
for...of: Wenn Sie nur die Werte brauchen (häufigster Fall)for mit Index: Wenn Sie den Index brauchen oder rückwärts iterieren wollenFunktionen fassen wiederverwendbaren Code in einem Block zusammen:
// Funktionsdeklaration
function begruessung(name) {
return `Hallo ${name}, willkommen im Archiv!`;
}
// Aufruf
const text = begruessung('Hugo Schuchardt');
console.log(text);
// "Hallo Hugo Schuchardt, willkommen im Archiv!"
Funktion mit mehreren Parametern:
function briefInfo(absender, empfaenger, jahr) {
return `Brief von ${absender} an ${empfaenger} (${jahr})`;
}
console.log(briefInfo('Schuchardt', 'Vossler', 1904));
// "Brief von Schuchardt an Vossler (1904)"
Funktion ohne Rückgabewert:
function zeigeWarnung(meldung) {
console.warn(`Warnung: ${meldung}`);
// kein return — gibt implizit undefined zurück
}
zeigeWarnung('Brief nicht gefunden');
Kurzschreibweise für Funktionen mit dem Pfeil-Operator =>:
// Klassische Funktion
function begruessung(name) {
return `Hallo ${name}`;
}
// Arrow Function (gleiche Funktion)
const begruessung = (name) => {
return `Hallo ${name}`;
};
// Kurzform: Bei einem Ausdruck kann man { } und return weglassen
const begruessung = (name) => `Hallo ${name}`;
// Bei einem Parameter kann man auch ( ) weglassen
const begruessung = name => `Hallo ${name}`;
Arrow Functions in der Praxis:
const jahre = [1879, 1892, 1904, 1910];
// Array filtern: nur Jahre nach 1900
const nachNeunzehnhundert = jahre.filter(j => j > 1900);
console.log(nachNeunzehnhundert); // [1904, 1910]
// Array transformieren: Alter berechnen (von 1927 aus)
const alter = jahre.map(j => 1927 - j);
console.log(alter); // [48, 35, 23, 17]
Das DOM ist die Baumstruktur, die der Browser aus dem HTML erzeugt:
HTML-Code: DOM-Baum:
<html> document
<body> └─ html
<h1>Titel</h1> └─ body
<p>Text</p> ├─ h1
</body> │ └─ "Titel"
</html> └─ p
└─ "Text"
Wichtige Begriffe:
<h1>, <p>, <div>)JavaScript greift über das DOM auf die HTML-Seite zu und kann sie verändern!
Um ein Element zu verändern, müssen wir es zuerst finden:
// Per CSS-Selektor (moderne Methode — empfohlen!)
const titel = document.querySelector('h1');
const absatz = document.querySelector('.brief-text');
const box = document.querySelector('#info-box');
// Alle passenden Elemente finden
const alleParagraphen = document.querySelectorAll('p');
console.log(alleParagraphen.length); // z.B. 5
// Ältere Methoden (funktionieren, aber querySelector ist flexibler)
const element = document.getElementById('info-box');
const elemente = document.getElementsByClassName('brief');
querySelector vs. querySelectorAll:
querySelector() — gibt das erste passende Element zurückquerySelectorAll() — gibt alle passenden Elemente als NodeList zurück// Über alle gefundenen Elemente iterieren
const items = document.querySelectorAll('li');
for (const item of items) {
console.log(item.textContent);
}
Inhalte ändern:
const titel = document.querySelector('h1');
titel.textContent = 'Neuer Titel'; // Nur Text
titel.innerHTML = '<em>Neuer</em> Titel'; // Mit HTML
CSS-Klassen steuern:
const box = document.querySelector('.brief');
box.classList.add('hervorgehoben'); // Klasse hinzufügen
box.classList.remove('versteckt'); // Klasse entfernen
box.classList.toggle('aktiv'); // Klasse umschalten
console.log(box.classList.contains('aktiv')); // true/false
Styles direkt setzen:
titel.style.color = 'darkred';
titel.style.fontSize = '2rem';
titel.style.backgroundColor = '#f0f0f0';
Neue Elemente erstellen:
const neuerAbsatz = document.createElement('p');
neuerAbsatz.textContent = 'Dieser Absatz wurde mit JS erstellt.';
document.querySelector('main').appendChild(neuerAbsatz);
Events sind Aktionen, auf die unser Code reagiert:
const button = document.querySelector('#mein-button');
button.addEventListener('click', function() {
console.log('Button wurde geklickt!');
alert('Hallo!');
});
// Kurzform mit Arrow Function
button.addEventListener('click', () => {
console.log('Klick!');
});
Wichtige Events:
| Event | Wann? | Typisches Element |
|---|---|---|
click | Element angeklickt | Button, Link, Bild |
input | Wert in Eingabefeld ändert sich | input, textarea |
submit | Formular abgeschickt | form |
mouseover | Maus über Element | Jedes Element |
keydown | Taste gedrückt | input, document |
Ein vollständiges Beispiel — HTML und JavaScript zusammen:
<!-- HTML -->
<h1 id="titel">Hugo Schuchardt Archiv</h1>
<p id="info">Klicken Sie auf einen Button.</p>
<button id="btn-bio">Biografie zeigen</button>
<button id="btn-briefe">Briefe zeigen</button>
// JavaScript
const info = document.querySelector('#info');
const btnBio = document.querySelector('#btn-bio');
const btnBriefe = document.querySelector('#btn-briefe');
btnBio.addEventListener('click', () => {
info.textContent = 'Hugo Schuchardt (1842-1927) war ein '
+ 'österreichischer Sprachwissenschaftler in Graz.';
info.style.color = 'darkgreen';
});
btnBriefe.addEventListener('click', () => {
info.innerHTML = 'Schuchardt hinterließ über '
+ '<strong>13.000 Briefe</strong> an Fachkollegen '
+ 'in ganz Europa.';
info.style.color = 'darkblue';
});
Dieses Muster — Element finden, Event binden, DOM ändern — verwenden Sie ständig!
JavaScript kann XML direkt im Browser parsen — ohne externe Bibliotheken:
const xmlString = `
<brief>
<absender>Hugo Schuchardt</absender>
<empfaenger>Karl Vossler</empfaenger>
<datum>1904-01-03</datum>
<text>Verehrter Herr Kollege!</text>
</brief>
`;
// XML-String in ein DOM-Dokument umwandeln
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, 'application/xml');
// Daten extrahieren — wie bei HTML querySelector!
const absender = xmlDoc.querySelector('absender').textContent;
const datum = xmlDoc.querySelector('datum').textContent;
console.log(absender); // "Hugo Schuchardt"
console.log(datum); // "1904-01-03"
DOMParser erzeugt aus einem XML-String einen Baum — genau wie der Browser aus HTML!
Schritt 1: TEI-XML laden (hier als String, alternativ mit fetch):
const teiXml = `
<TEI xmlns="http://www.tei-c.org/ns/1.0">
<teiHeader>
<fileDesc>
<titleStmt>
<title>Brief an Karl Vossler</title>
</titleStmt>
</fileDesc>
</teiHeader>
<text>
<body>
<opener>
<dateline>Graz, 3. Jänner 1904</dateline>
<salute>Verehrter Herr Kollege!</salute>
</opener>
<p>Empfangen Sie meinen Dank...</p>
<closer>
<signed>Ihr Hugo Schuchardt</signed>
</closer>
</body>
</text>
</TEI>`;
Schritt 2: Parsen und Daten extrahieren:
const parser = new DOMParser();
const doc = parser.parseFromString(teiXml, 'application/xml');
const titel = doc.querySelector('title').textContent;
const datum = doc.querySelector('dateline').textContent;
const gruss = doc.querySelector('salute').textContent;
const text = doc.querySelector('body p').textContent;
const signatur = doc.querySelector('signed').textContent;
Schritt 3: Extrahierte Daten als HTML rendern:
// Zielbereich im HTML
const ausgabe = document.querySelector('#brief-ausgabe');
// HTML zusammenbauen mit Template Literals
ausgabe.innerHTML = `
<article class="brief">
<h2>${titel}</h2>
<p class="brief-datum">${datum}</p>
<p class="brief-gruss">${gruss}</p>
<div class="brief-text">
<p>${text}</p>
</div>
<p class="brief-signatur">${signatur}</p>
</article>
`;
Der vollständige Ablauf:
DOMParser → XML-DOMquerySelector → Einzelne WerteinnerHTMLDieses Muster — Daten laden, verarbeiten, darstellen — ist das Fundament jeder Web-Anwendung!
Code Literacy (CL) bedeutet: generierten Code lesen und verstehen können.
Strategie zum Code-Lesen:
Prompt für Code Literacy:
Erkläre mir diesen JavaScript-Code Zeile für Zeile.
Was macht jede Zeile? Welche Konzepte werden verwendet?
Verwende einfache Sprache für JavaScript-Anfänger.
Sie müssen Code nicht auswendig schreiben können — aber Sie müssen ihn lesen und verstehen können!
Code Review (RV) bedeutet: generierten Code systematisch auf Fehler prüfen.
Häufige Fehler in LLM-generiertem JavaScript:
defer)== statt ===, String statt Numbervar statt let/constReview-Checkliste:
const/let korrekt verwendet?Die Konsole ist Ihr bester Freund beim Debugging:
// 1. Werte überprüfen
console.log('Titel:', titel);
console.log('Typ:', typeof titel);
// 2. Zwischen-Ergebnisse prüfen
const elemente = document.querySelectorAll('.brief');
console.log('Gefundene Elemente:', elemente.length);
// 3. Objekte inspizieren
console.log('Brief-Objekt:', brief);
console.table(briefe); // Schöne Tabelle in der Konsole
Browser DevTools — wichtige Features:
Typische Fehlermeldungen:
// "Cannot read property 'textContent' of null"
// → querySelector hat kein Element gefunden! Selektor prüfen.
// "x is not defined"
// → Variable existiert nicht. Tippfehler? Scope-Problem?
// "x is not a function"
// → Falscher Typ. Variable ist kein Function-Objekt.
Was haben wir heute gelernt?
const (Standard) und let (veränderbar)+, -, ===, !==, &&, ||if/else, for, for...ofquerySelector, textContent, classList, addEventListenerDOMParser für TEI-XML im BrowserÜbungen:
Fragen? Dann viel Spaß bei den Übungen!