Kurz: Der Gültigkeitsbereich (Scope) bestimmt, wo eine Variable sichtbar ist.
Teil des Kurses JavaScript
Kapitel 12 von 40 im Kurs JavaScript. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.
Der Gültigkeitsbereich (Scope) bestimmt, wo eine Variable sichtbar ist.
Arten von Scope
| Scope | Gilt in | Erzeugt durch |
|---|---|---|
| global | im ganzen Programm | Deklaration außerhalb von allem |
| Funktion | in der Funktion | function |
| Block | zwischen { } | let, const in if, for usw. |
| Modul | in der Datei | ES-Module |
const 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); }Ausgabe:
überall nur hier nur im Block
ReferenceError
ReferenceErrorInnere Bereiche sehen äußere Variablen, nicht umgekehrt. Findet JavaScript einen Namen nicht im aktuellen Bereich, sucht es nach außen weiter (Scope-Kette).
Verdecken (Shadowing)
const x = "außen";
function g() {
const x = "innen"; // verdeckt das äußere x
return x;
}
console.log(g(), x);Ausgabe:
innen außenGlobale Variablen vermeiden
Globale Variablen kann überall jemand ändern. Halte Daten so lokal wie möglich.
Closures
Eine Closure entsteht, wenn eine innere Funktion Variablen der äußeren Funktion “mitnimmt”, auch nachdem die äußere längst fertig ist:
function zaehlerErstellen() {
let stand = 0;
return function () {
stand++;
return stand;
};
}
const a = zaehlerErstellen();
const b = zaehlerErstellen();
console.log(a(), a(), a());
console.log(b());Ausgabe:
1 2 3
1stand ist von außen nicht erreichbar, nur über die zurückgegebene Funktion. Jeder Aufruf von zaehlerErstellen erzeugt einen eigenen stand. Closures dienen als private Variablen.
Praktisch: Funktionen mit Gedächtnis
function einmalig(fn) {
let schonGelaufen = false, ergebnis;
return (...args) => {
if (!schonGelaufen) { ergebnis = fn(...args); schonGelaufen = true; }
return ergebnis;
};
}
const init = einmalig(() => { console.log("initialisiere"); return 42; });
console.log(init(), init());
function cache(fn) {
const gemerkt = new Map();
return n => gemerkt.has(n) ? gemerkt.get(n) : (gemerkt.set(n, fn(n)), gemerkt.get(n));
}
const langsamQuadrat = n => { console.log("rechne", n); return n * n; };
const schnell = cache(langsamQuadrat);
console.log(schnell(9), schnell(9));Ausgabe:
initialisiere
42 42
rechne 9
81 81Die berühmte Schleifenfalle mit var
const mitVar = [];
for (var i = 0; i < 3; i++) mitVar.push(() => i);
const mitLet = [];
for (let j = 0; j < 3; j++) mitLet.push(() => j);
console.log(mitVar.map(f => f()), mitLet.map(f => f()));Ausgabe:
[ 3, 3, 3 ] [ 0, 1, 2 ]Mit var teilen sich alle Funktionen dieselbe Variable i (am Ende 3). Mit let bekommt jeder Durchlauf eine eigene Variable.
Module als Gültigkeitsbereich
Seit ES-Modulen hat jede Datei ihren eigenen Scope; nur was du mit export freigibst, ist außen sichtbar (eigenes Kapitel).
Merke
- Scope-Kette: Von innen nach außen wird nach Namen gesucht
letundconstgelten im Block,varin der Funktion- Eine Closure behält Zugriff auf die Variablen ihrer Entstehung
- Closures erzeugen private Zustände, Caches und Fabriken
- Globale Variablen vermeiden
Übungsaufgabe
Baue mit einer Closure einen Zähler mit den Methoden erhoehen(), verringern() und wert(), dessen Stand von außen nicht direkt veränderbar ist.
Quiz zur Selbstkontrolle
Was ist eine Closure?
- Eine Funktion, die Variablen ihrer Entstehungsumgebung behält (richtig)
- Eine Funktion ohne Parameter
- Eine geschlossene Datei
- Eine Schleife
Wo gilt eine mit let deklarierte Variable?
- Im umgebenden Block (richtig)
- Überall
- Nur in Funktionen
- Nur global
Wo sucht JavaScript nach einem Variablennamen?
- Von innen nach außen entlang der Scope-Kette (richtig)
- Nur global
- Von außen nach innen
- Nur im Block
Weiter im Kurs
Zurück: Arrow-Funktionen
Weiter: Arrays
Alle Kapitel: JavaScript im Überblick