📦Scope, Closures, this und Prototypen
Wo ist eine Variable sichtbar? Warum „merkt“ sich eine Funktion Werte? Wer ist this? Und woher kommen Methoden, die ein Objekt gar nicht selbst hat?
🪆Scope-Kette als verschachtelte Kästen
1const app = "VisualJS";2function aussen() {3 const x = 1;4 function mitte() {5 const y = 2;6 function innen() {7 const z = 3;8 console.log(app, x, y, z);9 }10 innen();11 }12 mitte();13}14aussen();
Klicke eine Codezeile an, um den aktuellen Scope zu wählen.
Gefunden in aussen() nach 3 Schritten.
Die Kästen werden aus dem Code berechnet. Gesucht wird immer von innen nach außen – nie nach innen oder zur Seite.
🎒Closures
Zähler mit privatem Zustand
1function erzeugeZaehler() {2 let stand = 0;3 return function () {4 stand++;5 return stand;6 };7}8const z1 = erzeugeZaehler();9const z2 = erzeugeZaehler();10console.log(z1(), z1(), z1());11console.log(z2());
Jeder Aufruf von erzeugeZaehler legt eine neue Umgebung mit eigenem stand an. Die zurückgegebene Funktion hält sie fest – auch nachdem erzeugeZaehler längst zurückgekehrt ist.
Schleife mit var
1for (var i = 0; i < 3; i++) {2 setTimeout(() => console.log("var:", i), 0);3}
Es gibt nur ein i (Funktions- bzw. globaler Scope). Wenn die Timer laufen, ist die Schleife längst fertig und i = 3.
Schleife mit let
1for (let i = 0; i < 3; i++) {2 setTimeout(() => console.log("let:", i), 0);3}
let in einem for-Kopf erzeugt pro Durchlauf eine neue Bindung. Jeder Callback schließt „sein“ i ein.
Modul-Muster: öffentlich und privat
1const konto = (() => {2 let saldo = 0;3 return {4 einzahlen(betrag) { saldo += betrag; return saldo; },5 get stand() { return saldo; },6 };7})();8konto.einzahlen(50);9console.log(konto.stand, konto.saldo);
saldo ist nur über die Closure erreichbar – von außen gibt es keine Eigenschaft konto.saldo.
Warum var in der Schleife 3, 3, 3 ergibt
👉this – wer ruft?
1const hund = {2 name: "Bello",3 wer() { return this; },4};5hund.wer();
Die Reihenfolge ist die Vorrangregel: Arrow-Funktionen ignorieren call/apply/bind komplett, bind schlägt call, new schlägt bind.
this wird bei normalen Funktionen erst beim Aufruf festgelegt – nicht bei der Definition.
setTimeout(obj.f), button.addEventListener("click", obj.f)), geht der Bezug zu obj verloren. Abhilfe: Arrow-Funktion drumherum (() => obj.f()) oder obj.f.bind(obj).🔗Die Prototypenkette
1class Tier {2 constructor(name) { this.name = name; }3 atmen() { return this.name + " atmet"; }4}5class Hund extends Tier {6 bellen() { return "Wuff!"; }7}8const bello = new Hund("Bello");