Module
als Präsentation ▻Neben Funktionen und Klassen gibt es noch eine weitere Möglichkeit Javascript Code zu strukturieren: Module. Wozu braucht man sie? Dazu ein Blick zurück in die Geschichte von Javascript:
▻Eine Webseite, viele Skripte
Häufig werden in einer Webseite Javascript-Programm aus verschiedenen Quellen kombiniert. Die Webseite enthält z.B.
- Javascript der Website selbst, zu Prüfung von Formulardaten und für Animationen
- für Zugriffs-Statistiken, z.B. Google Analytics
- für das Teilen von Inhalten aus Sozialen Netzwerkden, z.B. Instagram Embed
- für Feedback zu Webseite z.B. UserVoice
- für Kommentare auf der Webseite, z.B. Disqus
- für das Einbinden einer Landkarte, z.B. mit maplibre.js
Mit ein bisschen Copy-und-Paste kann man die verschiedenen Programme schnell in die eigene Webseite einbauen.
Aber achtung: all diese Programme laufen dann im selben Javascript Interpreter ab, und benutzen einen gemeinsamen globalen Namensraum.
▻Javascript ohne Module
Im “klassischen” Javascript kann Code mit dem script
Tag aus verschiedenen
Dateien geladen und zu einem Programm zusammen gesetzt werden.
Dabei gibt es nur einen Namensraum für den gesamten Code:
<h1>Diekt in der HTML Datei</h1>
<script>let a = 10;</script>
<script src="meinskript.js"></script>
<script>
console.log("kann b sehen", b);
b += 10;
console.log("kann b verändern", b);
</script>
Javascript Code Datei meinskript.js
let b = 2000;
console.log("kann a sehen", a);
a += 10;
console.log("kann a verändern", a);
Probleme ohne Module
Dieser gemeinsame Namensraum bringt viele Probleme: z.B. wenn ich ein fertiges Skript verwenden will, aber zufällig die gleichen Variablennamen oder Funktionsnamen selber schon verwendet habe.
▻Javascript mit Modulen
Um Module im Browser zu verwenden, muss im script
Tag
das Attribut type
gesetzt sein:
<script type="module">
let a = 1;
</script>
import
Das Einbinden von externem Code erfolgt nun nicht mehr mit
dem script
Tag, sondern mit einem import
Statement:
<script type="module">
let a = 1;
import { b, setB } from './meinmodule.js';
</script>
Dabei wird genau angegeben, welche Variablen, Funktionen, Klassen ich aus der anderen Datei verwenden will.
Achtung: schon die HTML-Datei muss eine http oder https URL haben, ebenso die geladenen Javascript Dateien.
Mit einer file-URL erhält man eine Fehlermeldung:
▻Quellübergreifende (Cross-Origin) Anfrage blockiert: Die Gleiche-Quelle-Regel verbietet das Lesen der externen Ressource auf file:///…boardgame-counter/counter-7b.js. (Grund: CORS-Anfrage war nicht http). A Modul-Quell-URI ist in diesem Dokument nicht erlaubt: “file:///…index-7b.html”.
Nur die importierten Dinge sind dann zugänglich:
<script type="module">
let a = 1;
import { b, setB } from './meinmodule.js';
console.log(b); // Variable ist lesbar
// b += 10; // funktioniert nicht, importiert ist wie const
setB(42); // Funktion kann aufgerufen werden
</script>
Eine Zuweisung auf die Variable b
ist aber nicht möglich,
sie verhält sich hier wie eine const
.
export
In der importierten Datei sind vielleicht viele Variablen, Klassen,
Funktionen vorhanden. Aber nur diejenigen, die eine
einer export
Deklaration haben stehen für einen Import zur Verfügung:
Javascript Code Datei meinmodule.js
export let b = 10;
let c = 'super secret';
Die Variable b
wird exportiert. Hier ist sie wirklich eine Variable, und kann
verändert werden.
Die Variable c
wird nicht exportiert, und kann
in der HTML-Datei oder in anderen Modulen nicht verwendet werden.
export von Funktionen
Javascript Code Datei meinmodule.js
export let b = 10;
let c = 'super secret';
export function setB( newValue ) {
b = newValue;
}
Die Funktion setB
wird exportiert. Sie hat Zugriff auf die
Variable b
und kann sie verändern.
export Deklarationen zusammenfassen
Man könnte die export-Deklarationen am Ende des Module zusammenfassen:
Javascript Code Datei meinmodule.js
let b = 10;
let c = 'super secret';
function setB( newValue ) {
b = newValue;
}
export { b, setB };
Developer Tools
Achtung: wenn wir Module verwenden gibt es kaum noch echte globale Variablen, die wir in den Developer Tools, in der Konsole direkt ausgeben können.
Statt dessen muss man auf den echten Debugger zurückgreifen, und einen Breakpoint setzen:
Module zur Strukturierung
Mit diesem einfachen Mechanismus der Module kann man nun die Probleme des gemeinsamen Namensraumes vermeiden, und größere Programme in Teile zerlegen.
Da in einem Modul alle importe und export explizit angeführt sind, muss man (fast) nichts über das restliche Programm wissen, um ein einzelnes Module zu verstehen.
▻