Web Engineering · DHBW Stuttgart
JavaScript im Browser und in Node.js
JavaScript ist eine Programmiersprache, definiert durch den ECMAScript-Standard. Ausgeführt wird sie von einer Laufzeitumgebung: im Browser oder durch Node.js auf dem Server. Beide verwenden dieselbe Sprach-Engine, stellen aber unterschiedliche Schnittstellen bereit — der Browser das DOM, Node.js den Zugriff auf Dateisystem, Netzwerk und Prozess. Diese Sitzung grenzt ab, was zur Sprache selbst gehört und was zur jeweiligen Umgebung.
Navigation: ← → · Leertaste weiter · 1–8 direkt · Pos 1/Ende
Sprache und Umgebung
ECMAScript-Kern und umgebungsspezifische APIs
Eine Laufzeitumgebung besteht aus der Sprach-Engine (etwa V8) und den von ihr bereitgestellten Schnittstellen. Der ECMAScript-Kern ist in Browser und Node.js identisch; die übrigen APIs unterscheiden sich. Die folgende Übersicht ordnet einzelne APIs der jeweiligen Umgebung zu.
APIs einordnen
Browser-Konsole und Node-REPL
Denselben Ausdruck in beiden Umgebungen auswerten
Links wird der Ausdruck direkt in dieser Seite ausgewertet, also im Browser. Rechts steht die Ausgabe, die das Node-REPL liefert. Der Vergleich zeigt, welche Objekte in welcher Umgebung definiert sind.
> Ausdruck wählen …
> Ausdruck wählen …
document und window bereit, Node den Zugriff auf Prozess und Dateisystem. Was eine Umgebung nicht definiert, führt dort zu einem ReferenceError.Browser-Umgebung
Das Document Object Model
Das Objekt document ist der Einstiegspunkt in das DOM — die Objektrepräsentation der geladenen Seite. Die folgenden Operationen verändern die Liste direkt; rechts steht der jeweils ausgeführte Aufruf. In Node existiert document nicht.
Live-Liste
- Komponente A
- Komponente B
- Komponente C
- Komponente D
Konsolen-Echo
> Befehl ausführen …
document nicht definiert; dieselben Aufrufe würden dort mit ReferenceError: document is not defined abbrechen.Serverseitiges JavaScript
Node.js: Dateisystem, Server und Prozess
Node.js führt JavaScript außerhalb des Browsers aus — mit derselben V8-Engine, aber serverseitigen Modulen. npm init erzeugt die package.json; darunter folgen die wichtigsten eingebauten Module im ESM-Format mit node:-Präfix.
$ npm init -y erzeugt die package.json. Ein Feld auswählen für die Erläuterung:
{
"name": "mein-projekt",
"version": "1.0.0",
"type": "module",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "node --watch index.js",
"test": "node --test"
},
"dependencies": {
"express": "^4.18.0"
}
}
Ein HTTP-Server kann nur serverseitig laufen; ein Browser kann selbst keinen Server bereitstellen.
import { createServer } from "node:http";
const server = createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/html" });
res.end("<h1>Hallo Welt!</h1>");
});
server.listen(3000, () => {
console.log("Server läuft auf Port 3000");
});
Direkter Dateizugriff ist im Browser aus Sicherheitsgründen nicht möglich, in Node hingegen Standard.
import { readFile } from "node:fs/promises";
// Promise-API (modern, empfohlen)
const data = await readFile("data.json", "utf8");
console.log(JSON.parse(data));
Das process-Objekt existiert nur in Node und steuert u. a. Signale, Argumente, Umgebungsvariablen und Exit-Codes.
process.on("SIGINT", () => {
console.log("Received SIGINT. Closing server...");
server.close(() => process.exit(0));
});
process.exit(0); // 0 = Erfolg, 1 = Fehler
Der ECMAScript-Sprachkern
Moderne JavaScript-Syntax (ES2015+)
Diese Sprachmerkmale gehören zu ECMAScript und verhalten sich in Browser und Node identisch. Durchgängig wird modernes ES verwendet, ohne var. Ein Thema auswählen und den Code ausführen.
const TAX = 0.19; // konstant
let warenkorb = 100;
warenkorb += 50; // ✓ let ist veränderbar
// TAX = 0.07; // ✗ TypeError — const
{
let rabatt = 10; // lebt nur in diesem Block
}
// rabatt — außerhalb: ReferenceError
// Funktionsdeklaration mit Parametern, Rückgabewert
// und einem Standard-Parameter (satz)
function bruttoPreis(netto, satz = 0.19) {
return netto * (1 + satz);
}
bruttoPreis(100); // 119
bruttoPreis(100, 0.07); // 107 (satz überschrieben)
const preise = [19.99, 5, 12.5]; const summe = preise.reduce((a, b) => a + b, 0); const teuer = preise.filter(p => p > 10); const inklMwSt = preise.map(p => p * 1.19);
const user = { name: "Mara", rolle: "Admin", aktiv: true };
const { name, rolle } = user; // herauslösen
const kopie = { ...user, aktiv: false }; // kopieren + ändern
const [erster, ...rest] = [1, 2, 3, 4]; // Rest-Elemente
const name = "Mara";
const punkte = 42;
const text = `Hallo ${name}, du hast ${punkte} Punkte.`;
// Ausdrücke direkt im String — z. B. für CSS:
const css = `transform: rotate(${punkte / 2}deg);`;
// "Daten laden" liefert ein Promise
const ladeUser = () =>
new Promise(resolve =>
setTimeout(() => resolve({ name: "Mara" }), 400)
);
const user = await ladeUser(); // wartet, ohne zu blockieren
console.log(user.name);
// IIFE: erzeugt einen eigenen, privaten Gültigkeitsbereich
const counter = (() => {
let n = 0; // von außen nicht zugänglich
return { tick: () => ++n }; // tick() ist die einzige Schnittstelle
})();
counter.tick(); // 1
counter.tick(); // 2
Anwendungsbeispiel: Vanilla JavaScript
Logo-Generator
Diese Anwendung kombiniert die behandelten Konzepte: DOM-Zugriff, Event-Handling und moderne Syntax — ohne Framework. Die Regler verändern die Vorschau; das erzeugte CSS unten aktualisiert sich entsprechend und lässt sich kopieren.
Regler
Generiertes CSS
Verwendete Konzepte
const $ = id => document.getElementById(id)
Arrow Function und DOM-Zugriff: holt ein Element über seine ID.
$$("input, select, textarea").forEach(el => el.addEventListener("input", update))
Event-Handling: bindet alle Regler gemeinsam; bei jeder Eingabe wird update aufgerufen.
await navigator.clipboard.writeText(css)
Browser-API zum Kopieren in die Zwischenablage; in Node nicht verfügbar.
Ausblick auf die nächste Sitzung
Derselbe Zähler in vier Frameworks
Dasselbe Verhalten — ein klickbarer Zähler — umgesetzt in vier Ansätzen, vom Web-Standard bis zum Compiler. In der nächsten Sitzung wird diese Logik mit einem Framework nachgebaut.
Web-Standard, kein Framework — läuft nativ im Browser.
class MyCounter extends HTMLElement {
constructor() {
super();
this.count = 0;
}
connectedCallback() {
this.innerHTML = `<button>Clicked 0 times</button>`;
const btn = this.querySelector("button");
btn.addEventListener("click", () => {
this.count++;
btn.textContent = `Clicked ${this.count} times`;
});
}
}
customElements.define("my-counter", MyCounter);
Virtual DOM · JSX · Hooks (useState).
import { useState } from "react";
function MyButton() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
}
Reaktive refs · Single-File Components (.vue).
<script setup>
import { ref } from "vue";
const count = ref(0);
</script>
<template>
<button @click="count++">
Clicked {{ count }} times
</button>
</template>
Compiler — kein Runtime-Framework, reaktive Zuweisungen.
<script>
let count = 0;
</script>
<button on:click={() => count += 1}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>