Abschnitt 17 · Lektion 1
localStorage
Alles, was dein Code bisher gemerkt hat, war beim nächsten Neuladen weg. Variablen leben, solange die Seite lebt, und keine Sekunde länger.
localStorage ist ein kleiner Kasten, in dem etwas liegen bleibt. Er überlebt das Neuladen, das Schließen des Tabs und den Neustart des Rechners.
Fünf Zugriffe, mehr gibt es nicht
<p>Sieh in die Console und lad die Seite danach neu. Der Eintrag ist noch da.</p> body {
font-family: system-ui, sans-serif;
max-width: 40rem;
margin: 0;
padding: 1rem;
line-height: 1.6;
color: #1c1917;
}
p {
margin: 0 0 0.75rem;
} localStorage.setItem("name", "Mario");
localStorage.setItem("kurs", "javascript");
console.log("name:", localStorage.getItem("name"));
console.log("Anzahl der Einträge:", localStorage.length);
console.log("Der erste Schlüssel heißt:", localStorage.key(0));
localStorage.removeItem("kurs");
console.log("kurs nach removeItem:", localStorage.getItem("kurs"));
console.log("Anzahl jetzt:", localStorage.length);
// clear leert alles. In einer echten Anwendung ist das grob:
// dort liegen auch die Einträge anderer Teile der Seite.
localStorage.clear();
console.log("Anzahl nach clear:", localStorage.length);
// Und noch einmal etwas ablegen, damit beim Neuzeichnen
// etwas da ist.
localStorage.setItem("name", "Mario"); localStorage.setItem(schluessel, wert) legt etwas ab.
localStorage.getItem(schluessel) holt es wieder.
localStorage.removeItem(schluessel) löscht einen Eintrag.
localStorage.clear() löscht alles. Vorsicht damit: In einer echten Anwendung liegen dort auch die Einträge anderer Teile der Seite, und clear fragt nicht nach.
localStorage.length und localStorage.key(n) sagen dir, wie viel drin ist und wie der Schlüssel an einer bestimmten Stelle heißt. Beides braucht man selten.
Probier das erste Beispiel aus und klick danach auf Seite neu laden. Der Eintrag ist noch da. Genau das ist der Unterschied zu allem, was du bisher gemacht hast: Bis hierhin war nach dem Neuladen jedes Mal alles weg.
In den Kasten sehen kannst du jederzeit selbst. Tipp in die Eingabezeile der Console localStorage.getItem("name"), und darüber steht Mario. localStorage.length antwortet mit 1, Object.keys(localStorage) mit ["name"], und schreibst du nur localStorage hin, kommt der ganze Bestand als {name: "Mario"} zurück. Das ist derselbe Kasten, in den der Code daneben geschrieben hat, und diese vier Zeilen sind in diesem Abschnitt dein wichtigstes Werkzeug: Sie beantworten die Frage „was liegt da eigentlich wirklich”, und die stellt sich hier ständig.
Die Falle dieses ganzen Abschnitts
<p>Eine Zahl geht hinein, ein Text kommt heraus.</p> body {
font-family: system-ui, sans-serif;
max-width: 40rem;
margin: 0;
padding: 1rem;
line-height: 1.6;
color: #1c1917;
}
p {
margin: 0 0 0.75rem;
} localStorage.setItem("zaehler", 41);
localStorage.setItem("angemeldet", false);
const zaehler = localStorage.getItem("zaehler");
const angemeldet = localStorage.getItem("angemeldet");
console.log("zaehler:", zaehler, typeof zaehler);
console.log("angemeldet:", angemeldet, typeof angemeldet);
// Und damit rechnet es sich schlecht.
console.log("Plus eins, falsch:", zaehler + 1);
console.log("Plus eins, richtig:", Number(zaehler) + 1);
// Der Wahrheitswert ist noch tückischer: der Text "false"
// ist nicht leer und damit truthy.
if (angemeldet) {
console.warn("Dieser Zweig läuft, obwohl false gespeichert wurde.");
}
console.log("Richtig geprüft:", angemeldet === "true"); Was hineingeht, kommt als Text zurück. Immer. Ohne Ausnahme.
Du schreibst die Zahl 41 hinein und bekommst die Zeichenfolge "41" zurück. Rechnest du damit weiter, hängt + 1 einfach eine Eins an und du hast "411". Der Fehler wirft nicht, er rechnet nur falsch, und du suchst ihn an der falschen Stelle.
Beim Wahrheitswert ist es noch unangenehmer. Du schreibst false hinein und bekommst "false" zurück, und das ist ein nicht leerer Text und damit truthy (Lektion 3.3). Ein if darauf läuft also in den falschen Zweig.
Der Ausweg ist immer derselbe: beim Lesen zurückverwandeln. Number(...) für Zahlen, ein Vergleich mit === "true" für Wahrheitswerte. Für alles, was komplizierter ist als das, gibt es die nächste Lektion.
null, nicht undefined
<p>Ein Schlüssel, den nie jemand gesetzt hat.</p> body {
font-family: system-ui, sans-serif;
max-width: 40rem;
margin: 0;
padding: 1rem;
line-height: 1.6;
color: #1c1917;
}
p {
margin: 0 0 0.75rem;
} const fehlt = localStorage.getItem("gibtesnicht");
console.log("Wert:", fehlt);
console.log("Typ:", typeof fehlt);
console.log("Ist es undefined?", fehlt === undefined);
console.log("Ist es null?", fehlt === null);
// Deshalb greift ?? und liefert den Standardwert.
const sprache = localStorage.getItem("sprache") ?? "de";
console.log("Sprache:", sprache);
// Achtung beim Unterschied zu ||. Ein absichtlich leerer
// Text wäre bei || weg, bei ?? bleibt er.
localStorage.setItem("notiz", "");
console.log("Mit ??:", JSON.stringify(localStorage.getItem("notiz") ?? "Standard"));
console.log("Mit ||:", JSON.stringify(localStorage.getItem("notiz") || "Standard")); Fragst du nach einem Schlüssel, den es nicht gibt, bekommst du null zurück. Nicht undefined, was du vielleicht erwarten würdest, und was ein Objekt bei einer fehlenden Eigenschaft liefern würde.
Praktisch spielt der Unterschied selten eine Rolle, denn ?? aus Lektion 3.4 greift bei beidem. Ein Standardwert ist damit eine Zeile lang.
Der Unterschied zu || ist hier trotzdem wichtig. Ein absichtlich leerer Text ist ein gültiger gespeicherter Wert, und || würde ihn durch den Standardwert ersetzen, ?? nicht. Im dritten Beispiel stehen beide Fassungen untereinander.
Der Kasten gehört zur Domain
localStorage gehört nicht zu einer einzelnen Seite, sondern zum Origin, also zur Kombination aus Protokoll, Domain und Port.
Daraus folgt zweierlei. Alle Seiten deiner Website teilen sich denselben Speicher, und was auf der einen Seite abgelegt wird, ist auf der anderen lesbar. Und der Speicher einer fremden Domain ist für dich unsichtbar, auch wenn deren Seite in einem Rahmen auf deiner steckt.
Weil alle Seiten sich denselben Kasten teilen, kollidieren Schlüssel wie name oder daten früher oder später. Deshalb gibt man ihnen ein Präfix.
Diese Lernplattform hat zwei Einträge, und sie zeigen beide Seiten davon. Der eine heißt lern:queue und ist die Warteschlange deiner noch nicht gemeldeten Fortschritte, der andere heißt schlicht theme und merkt sich hell oder dunkel. Der zweite ist genau die Sorte Name, um die sich zwei Teile einer Seite irgendwann streiten.
Der Kasten, in den du hier schreibst, ist übrigens nicht dieser, sondern ein eigener für jede Aufgabe und jedes Beispiel. Was es damit auf sich hat, steht in Lektion 17.3.
Und er läuft nie ab
Ein Eintrag im localStorage bleibt, bis ihn jemand löscht. Es gibt kein Ablaufdatum und keine automatische Bereinigung.
Wer etwas ablegt, das nur eine Weile gelten soll, muss den Zeitpunkt selbst dazuschreiben und beim Lesen selbst prüfen, ob er noch gilt. Das ist kein großer Aufwand, aber es passiert nicht von allein.
Wie viel dort hineinpasst und was auf keinen Fall hineingehört, steht in Lektion 17.3.
Zum Mitnehmen
Alles, was hineingeht, kommt als Text zurück. Auch die Zahl, die du hineingeschrieben hast.
Jetzt du
Basis Konto, kostenlosZu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
Was in dieser Lektion steckt
-
Artikel mit 3 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.
-
Aufgabe im Editor, direkt im Browser geprüft
Öffnet sich mit dem Basis Konto.