Die Sprache des Webs, im Browser und auf dem Server
Ausführen: Im Browser mit F12 die Konsole öffnen, oder mit Node.js: Datei hallo.js speichern und node hallo.js starten. Viele Beispiele kannst du hier direkt mit "Probier es selbst" ausführen.
console.log() gibt Werte in der Konsole aus;// für eine Zeile, /* ... */ für mehrereconsole.log("Hallo, Welt!");
console.log("Ich lerne JavaScript.");const für Werte, die nicht neu zugewiesen werden; let für veränderlichevar vermeidenconst schützt nur die Zuweisung, nicht den Inhalt von Arrays und Objektenundefinedlet alter = 17;
const name = "Mia";
console.log(name, "ist", alter);
alter = 18; // let erlaubt Änderungen
console.log(name, "ist jetzt", alter);typeof liefert den Typ; typeof null ist "object"Number(), String(), Boolean() wandeln explizit um"5" + 3 ergibt "53", "5" - 3 ergibt 2console.log(typeof 42);
console.log(typeof 3.14);
console.log(typeof "Text");
console.log(typeof true);
console.log(typeof undefined);
console.log(typeof null); // Historischer Fehler: "object"
console.log(typeof [1, 2]); // Arrays sind Objekte
console.log(typeof {a: 1});
console.log(typeof function () {});
console.log(typeof 10n);number für Zahlen (und BigInt für riesige ganze Zahlen)% gibt den Rest, ** die Potenz0.1 + 0.2 !== 0.3: Kommazahlen mit Toleranz vergleichenMath.round/floor/ceil/trunc runden verschieden; toFixed formatiertMath.random() liefert 0 bis unter 1; Number.isNaN prüft auf NaNconsole.log(7 / 2, 7 % 2, 2 ** 10);
console.log(10 / 0, -10 / 0, 0 / 0);
console.log(Number.MAX_SAFE_INTEGER);
console.log(Number.EPSILON > 0);=== und !== verwenden&&, || liefern einen der Operanden (Kurzschluss)?? ersetzt nur null/undefined, || jeden falsy Wert?. verhindert Fehler bei fehlenden Zwischenwertenbedingung ? a : b ist die Kurzform von if/elseconsole.log(5 === 5, 5 === "5", 5 == "5");
console.log(0 == false, 0 === false);
console.log(null == undefined, null === undefined);
console.log("a" < "b", "B" < "a", "10" < "9", 10 < 9); Hallo ${name} `slice, split, replaceAll, trim, includes, padStart sind AlltagswerkzeugelocaleCompare sortierst du sprachrichtiglength 2: mit [...text] richtig zählenconst name = "Mia", alter = 17;
console.log(`Hallo ${name}, in einem Jahr bist du ${alter + 1}.`);
console.log(`Zeile 1
Zeile 2`);
console.log("Tab:\tText\nNeue Zeile, \"Anführungszeichen\", \\ Backslash");if, else if, else: nur der erste passende Zweig läuftswitch vergleicht mit === und braucht breakconst punkte = 73;
if (punkte >= 90) {
console.log("sehr gut");
} else if (punkte >= 75) {
console.log("gut");
} else if (punkte >= 50) {
console.log("bestanden");
} else {
console.log("nicht bestanden");
}for für feste Anzahl, while für Bedingungen, do...while läuft mindestens einmalfor...of für Werte, for...in für Objektschlüsselbreak beendet, continue überspringt, Labels verlassen mehrere Ebenenfor (let i = 1; i <= 5; i++) {
console.log("Runde", i);
}function name(parameter) { return wert; }return ist das Ergebnis undefinedx = 1), Rest-Parameter (...args), Objekt-Parameterfunction begruessen(name) {
return "Hallo " + name + "!";
}
console.log(begruessen("Mia"));
console.log(begruessen("Tom"));(a, b) => a + b ist die Kurzform; bei einem Ausdruck entfallen {} und return() => ({ ... })this von außenconst addiere = (a, b) => a + b;
const quadrat = x => x * x; // ein Parameter: Klammern optional
const hallo = () => "Hallo"; // keine Parameter
const rechne = (a, b) => { // Block: return nötig
const summe = a + b;
return summe * 2;
};
console.log(addiere(2, 3), quadrat(6), hallo(), rechne(1, 2));let und const gelten im Block, var in der Funktionconst global = "überall";
function f() {
const lokal = "nur hier";
if (true) {
const imBlock = "nur im Block";
console.log(global, lokal, imBlock);
}
try { console.log(imBlock); } catch (e) { console.log(e.name); }
}
f();
try { console.log(lokal); } catch (e) { console.log(e.name); }length ist die Anzahl; at(-1) ist das letzte Elementpush/pop arbeiten hinten, unshift/shift vorn, splice in der Mitteslice, Spread und structuredClone kopierensort() ohne Vergleichsfunktion sortiert Text, für Zahlen (a, b) => a - bincludes, find, some, every zum Suchen und Prüfenconst farben = ["rot", "grün", "blau"];
console.log(farben[0], farben[2], farben[5]);
console.log(farben.length);
farben[1] = "gelb";
farben[3] = "lila";
console.log(farben);
console.log(farben.at(-1)); // letztes Elementmap wandelt um, filter wählt aus, reduce fasst zusammenfilter, map, reduce ersetzen viele SchleifenflatMap, some, every, find, Object.groupBy ergänzen die Palettemap(parseInt): das zweite Argument ist der Index["a", "b", "c"].forEach((x, i) => console.log(i, x));.name oder ["name"]Object.keys/values/entries/fromEntries wandeln zwischen Objekt und Array{ ...a } kopiert flach, structuredClone tiefObject.freeze macht ein Objekt unveränderlichthis auf das Objekt; bind fixiert esconst person = {
name: "Mia",
alter: 17,
hobbys: ["Lesen", "Rad"],
adresse: { stadt: "Köln", plz: "50667" },
vorstellen() { return `Ich bin ${this.name}`; },
};
console.log(person.name, person["alter"]);
console.log(person.adresse.stadt, person.hobbys[1]);
console.log(person.vorstellen());const [a, b] = array und const { x, y } = objekt entpacken Wertex: neu), Standardwerte (x = 1), Rest (...rest)... verteilt Arrays/Objekte beim Erzeugen oder Aufrufen... sammelt übrige Werte beim Empfangenconst [a, b, c] = [10, 20, 30];
console.log(a, b, c);
const [erstes, , drittes] = ["x", "y", "z"]; // Lücke überspringt
console.log(erstes, drittes);
const [kopf, ...rest] = [1, 2, 3, 4];
console.log(kopf, rest);
const [p = 5, q = 6] = [1]; // Standardwerte
console.log(p, q);
let m = 1, n = 2;
[m, n] = [n, m]; // Tauschen
console.log(m, n);Set: Menge ohne Duplikate (add, has, delete, size)Map: Schlüssel-Wert mit beliebigen Schlüsseln, behält die Reihenfolge[...new Set(array)]WeakMap/WeakSet: schwache Verweise ohne Speicherlecksconst s = new Set([1, 2, 2, 3, 3, 3]);
console.log(s, s.size);
s.add(4); s.add(2);
console.log(s.has(4), s.has(9));
s.delete(1);
console.log([...s]);
console.log([...new Set("mississippi")].join(""));JSON.stringify macht aus Daten Text, JSON.parse aus Text Datenundefined gehen verloren, Datum wird zu Textparse bei fremden Daten in try/catch setzennull, 2 formatierst du lesbarstructuredClone ist die bessere Tiefenkopie{
"name": "Mia",
"alter": 17,
"hobbys": ["Lesen", "Rad"],
"aktiv": true,
"partner": null
}Date speichert Millisekunden seit 1970 (UTC)toISOString() liefert das ISO-Format; toLocaleDateString formatiert regionalconst jetzt = new Date();
console.log(jetzt instanceof Date, typeof Date.now());
const d1 = new Date(2025, 11, 24, 18, 30); // Monat 0-basiert! 11 = Dezember
const d2 = new Date("2025-03-08T14:30:00Z"); // ISO-Format, Z = UTC
const d3 = new Date(0);
console.log(d1.getFullYear(), d1.getMonth(), d1.getDate());
console.log(d2.toISOString());
console.log(d3.toISOString());/muster/flags; g alle, i ohne Groß/Klein, m mehrzeiligtest, match, matchAll, replace, split sind die Hauptwerkzeuge( ) und benannte Gruppen (?<name> ) holen Teile heraus? nach Quantor macht ihn sparsam\ maskieren, Muster lesbar haltenconst text = "Meine Nummer ist 12345, deine 67890.";
console.log(/\d+/.test(text)); // gibt es Ziffern?
console.log(text.match(/\d+/)[0]); // erster Treffer
console.log(text.match(/\d+/g)); // alle Treffer (Flag g)
console.log(text.replace(/\d/g, "#"));class mit constructor, Methoden, get/set und static#nameextends und super für Vererbungthis: mit Arrow-Feld oder bind lösenclass Hund {
constructor(name, alter) {
this.name = name;
this.alter = alter;
}
bellen() {
return `${this.name} sagt: Wuff!`;
}
get menschenJahre() {
return this.alter * 7;
}
}
const rex = new Hund("Rex", 3);
console.log(rex.bellen(), rex.menschenJahre);
console.log(rex instanceof Hund, typeof Hund);try { } catch (e) { } finally { } fängt Fehler ab und räumt aufthrow new Error("Text") löst Fehler ausTypeError, ReferenceError, RangeError, SyntaxErrorclass X extends Errortry {
console.log("vorher");
JSON.parse("{kaputt");
console.log("wird nie erreicht");
} catch (fehler) {
console.log("Fehler:", fehler.name);
} finally {
console.log("läuft immer");
}
console.log("Programm läuft weiter");export gibt frei, import holt ins Modul<script type="module">import) oder CommonJS (require)import() lädt dynamisch bei Bedarf// mathe.js
export const PI = 3.14159;
export function quadrat(x) {
return x * x;
}
export class Rechner {
addiere(a, b) { return a + b; }
}
const geheim = 42; // nicht exportiert: von außen unsichtbar
export default function hauptfunktion() { // genau ein Default-Export pro Datei
return "Standard";
}[Symbol.iterator](), Iteratoren next()function* und yield erzeugen Werte nacheinander und pausieren dazwischenyield* delegiert an einen anderen Iterierbarenasync function* und for await...of für Datenströmeconst it = [10, 20][Symbol.iterator]();
console.log(it.next());
console.log(it.next());
console.log(it.next());.then() verkettet, .catch() fängt Fehler, .finally() räumt aufPromise.all, allSettled, race, any kombinieren mehrere Promisesconsole.log("1: Start");
setTimeout(() => console.log("3: nach 100 ms"), 100);
setTimeout(() => console.log("2b: nach 0 ms (trotzdem später!)"), 0);
console.log("2: Ende des Skripts");async macht eine Funktion zu einer, die ein Promise liefertawait wartet auf ein Promise, ohne das Programm zu blockierentry/catch abfangenPromise.all parallel ausführenfetch wirft bei 404/500 nicht: antwort.ok prüfenconst warte = (ms, wert) => new Promise(r => setTimeout(() => r(wert), ms));
async function ablauf() {
console.log("start");
const a = await warte(50, "A");
console.log("erhalten:", a);
const b = await warte(10, "B");
return a + b;
}
ablauf().then(erg => console.log("Ergebnis:", erg));
console.log("läuft schon weiter");setTimeout/setInterval mit clear... abbrechenlet n = 0;
const id = setInterval(() => {
n++;
console.log("Tick", n);
if (n === 3) {
clearInterval(id);
console.log("gestoppt");
}
}, 20);
const abbruch = setTimeout(() => console.log("wird nie ausgegeben"), 500);
clearTimeout(abbruch);querySelector(All) findet Elemente mit CSS-SelektorentextContent für Text (sicher), innerHTML nur mit vertrauenswürdigem HTMLcreateElement, append, remove bauen die Seite umclassList und dataset für Klassen und data-*-Attributedocument
└─ html
├─ head
└─ body
├─ h1 "Titel"
└─ ul
├─ li "Eins"
└─ li "Zwei"addEventListener("click", funktion) meldet eine Reaktion antarget, key, Position usw.preventDefault() verhindert das Standardverhalten (Link, Formular)<button id="b">Klick mich</button>
<p id="ausgabe">noch nichts</p>
<script>
const b = document.getElementById("b");
let zaehler = 0;
b.addEventListener("click", (event) => {
zaehler++;
document.getElementById("ausgabe").textContent =
`Klick Nr. ${zaehler} auf <${event.target.tagName.toLowerCase()}>`;
});
</script>FormData und Object.fromEntries holen alle Werte auf einmalvalue ist immer Text, bei Zahlen mit Number() umwandelnrequired, pattern und checkValidity() prüfen im Browser<form id="f">
<label>Name <input name="name" value="Mia"></label><br>
<label>Alter <input name="alter" type="number" value="17"></label><br>
<label><input name="newsletter" type="checkbox" checked> Newsletter</label><br>
<label>Farbe
<select name="farbe"><option>rot</option><option selected>blau</option></select>
</label><br>
<button>Senden</button>
</form>
<pre id="ausgabe"></pre>
<script>
document.getElementById("f").addEventListener("submit", (e) => {
e.preventDefault();
const daten = new FormData(e.target);
const objekt = Object.fromEntries(daten);
objekt.newsletter = e.target.newsletter.checked;
objekt.alter = Number(objekt.alter);
document.getElementById("ausgabe").textContent = JSON.stringify(objekt, null, 2);
});
</script>localStorage speichert dauerhaft nur Text; Objekte über JSONsessionStorage gilt nur für den Tabtry/catch setzen und Daten beim Lesen prüfenHttpOnly-CookieslocalStorage.setItem("name", "Mia");
console.log(localStorage.getItem("name")); // "Mia"
console.log(localStorage.getItem("gibtsnicht")); // null
localStorage.removeItem("name");
localStorage.clear(); // alles löschen
console.log(localStorage.length);URL und URLSearchParams zerlegen und bauen Adressen sicherIntersectionObserver & Co.) ersetzen Scroll-Abfragencrypto für Zufall mit Sicherheitsanspruch; Feature Detection statt Browser-Ratenconst url = new URL("https://beispiel.de/suche?q=java+script&seite=2#ergebnis");
console.log(url.hostname, url.pathname);
console.log(url.searchParams.get("q"), url.searchParams.get("seite"));
console.log(url.hash);
url.searchParams.set("seite", 3);
url.searchParams.append("tag", "neu");
console.log(url.toString());
console.log(new URLSearchParams({ a: 1, b: "x y" }).toString());
console.log(encodeURIComponent("Köln & Bonn"));canvas.getContext("2d") liefert den Zeichenkontext; Ursprung oben linksrequestAnimationFrame und Bewegung nach vergangener Zeit<canvas id="c" width="300" height="160" style="border:1px solid #888"></canvas>
<script>
const ctx = document.getElementById("c").getContext("2d");
ctx.fillStyle = "steelblue";
ctx.fillRect(20, 20, 100, 60); // x, y, Breite, Höhe
ctx.strokeStyle = "crimson";
ctx.lineWidth = 4;
ctx.strokeRect(140, 20, 100, 60);
ctx.beginPath();
ctx.arc(70, 120, 25, 0, Math.PI * 2); // Kreis: x, y, Radius, Start, Ende
ctx.fillStyle = "gold";
ctx.fill();
ctx.stroke();
ctx.font = "20px sans-serif";
ctx.fillStyle = "black";
ctx.fillText("Hallo Canvas", 130, 130);
</script>fs, http, process)fs/promises und path für Dateien und Pfadeprocess.argv, process.env für Argumente und UmgebungEventEmitter für Ereignissenode --version
npm --version
node hallo.js
node # interaktive Konsole (REPL)package.json beschreibt das Projekt, package-lock.json fixiert Versionennpm install installiert, npm run <name> führt Skripte aus, npx startet Werkzeuge^ erlaubt Minor- und Patch-Updatesnode_modules nicht ins Repositorynpm audit nutzenmkdir mein-projekt
cd mein-projekt
npm init -y # erzeugt package.json mit Standardwertennode --test, Vitest, Jest)async/await und assert.rejectsconst test = require("node:test");
const assert = require("node:assert/strict");
function istPalindrom(text) {
const sauber = text.toLowerCase().replace(/[^a-z0-9]/g, "");
return sauber === [...sauber].reverse().join("");
}
test("erkennt Palindrome", () => {
assert.equal(istPalindrom("Anna"), true);
assert.equal(istPalindrom("Ein Neger mit Gazelle zagt im Regen nie"), true);
});
test("erkennt Nicht-Palindrome", () => {
assert.equal(istPalindrom("Hallo"), false);
});
test("leerer Text ist ein Palindrom", () => {
assert.equal(istPalindrom(""), true);
});npm install -D eslint @eslint/js
npx eslint .
npx eslint . --fix # behebt, was automatisch gehtconst/let, ===, Template-Strings, async/awaitthis, flache Kopien, vergessene await, ObjektgleichheitinnerHTML; keine Geheimnisse im Frontend// Schlecht
function f(a) { if (a) { if (a.length > 0) { if (a[0] > 5) { return true; } } } return false; }
// Besser
const MIN_WERT = 5;
function ersterWertIstGross(liste) {
if (!liste?.length) return false;
return liste[0] > MIN_WERT;
}
console.log(f([9]), ersterWertIstGross([9]), ersterWertIstGross([]));textContent, try/catch beim Speichern und ARIA-Attribute gehören zur Grundausstattung<style>
body { font-family: system-ui, sans-serif; max-width: 420px; margin: 1rem auto; padding: 0 1rem; }
form { display: flex; gap: .5rem; }
input[type=text] { flex: 1; padding: .5rem; }
ul { list-style: none; padding: 0; }
li { display: flex; align-items: center; gap: .5rem; padding: .4rem 0; border-bottom: 1px solid #ddd; }
li.fertig span { text-decoration: line-through; color: #888; }
li span { flex: 1; }
.filter button[aria-pressed=true] { font-weight: bold; text-decoration: underline; }
</style>
<h1>Aufgaben</h1>
<form id="neu">
<label class="visually-hidden" for="text" style="position:absolute;left:-9999px">Neue Aufgabe</label>
<input type="text" id="text" placeholder="Was ist zu tun?" required maxlength="80">
<button>Hinzufügen</button>
</form>
<div class="filter" role="group" aria-label="Filter">
<button data-filter="alle" aria-pressed="true">Alle</button>
<button data-filter="offen" aria-pressed="false">Offen</button>
<button data-filter="fertig" aria-pressed="false">Erledigt</button>
</div>
<ul id="liste"></ul>
<p id="zaehler" role="status"></p>
<script>
const SCHLUESSEL = "todo-demo";
let aufgaben = lade();
let filter = "alle";
function lade() {
try {
const daten = JSON.parse(localStorage.getItem(SCHLUESSEL));
return Array.isArray(daten) ? daten.filter(a => a && typeof a.text === "string") : [];
} catch { return []; }
}
function speichere() {
try { localStorage.setItem(SCHLUESSEL, JSON.stringify(aufgaben)); } catch {}
}
function sichtbar() {
if (filter === "offen") return aufgaben.filter(a => !a.fertig);
if (filter === "fertig") return aufgaben.filter(a => a.fertig);
return aufgaben;
}
function zeichne() {
const liste = document.getElementById("liste");
liste.replaceChildren(); // Liste leeren
for (const a of sichtbar()) {
const li = document.createElement("li");
li.classList.toggle("fertig", a.fertig);
li.dataset.id = a.id;
const box = document.createElement("input");
box.type = "checkbox";
box.checked = a.fertig;
box.setAttribute("aria-label", "Erledigt: " + a.text);
const text = document.createElement("span");
text.textContent = a.text; // textContent: sicher gegen XSS
const weg = document.createElement("button");
weg.textContent = "×";
weg.setAttribute("aria-label", "Löschen: " + a.text);
li.append(box, text, weg);
liste.append(li);
}
const offen = aufgaben.filter(a => !a.fertig).length;
document.getElementById("zaehler").textContent =
offen === 1 ? "1 Aufgabe offen" : `${offen} Aufgaben offen`;
}
document.getElementById("neu").addEventListener("submit", (e) => {
e.preventDefault();
const feld = document.getElementById("text");
const text = feld.value.trim();
if (!text) return;
aufgaben.push({ id: Date.now(), text, fertig: false });
feld.value = "";
speichere(); zeichne();
});
// Event Delegation: ein Listener für alle Einträge
document.getElementById("liste").addEventListener("click", (e) => {
const li = e.target.closest("li");
if (!li) return;
const id = Number(li.dataset.id);
if (e.target.matches("input[type=checkbox]")) {
const a = aufgaben.find(x => x.id === id);
a.fertig = e.target.checked;
} else if (e.target.matches("button")) {
aufgaben = aufgaben.filter(x => x.id !== id);
} else return;
speichere(); zeichne();
});
document.querySelector(".filter").addEventListener("click", (e) => {
const knopf = e.target.closest("button[data-filter]");
if (!knopf) return;
filter = knopf.dataset.filter;
for (const b of document.querySelectorAll(".filter button")) {
b.setAttribute("aria-pressed", String(b === knopf));
}
zeichne();
});
zeichne();
</script>