Question 1Que se passe-t-il si tu exécutes localStorage.getItem("theme") avec une clé qui n'a jamais été enregistrée ?
localStorage — enregistrer des données dans le navigateur
Enregistrer des valeurs dans le navigateur avec setItem, getItem et removeItem, stocker les tableaux en JSON, et gérer null et la limite de taille.
Si tu gardes les articles du panier ou les réglages d'affichage d'un utilisateur dans des variables, ils disparaissent quand la page est rechargée ou fermée, et tout revient à l'état initial à la prochaine ouverture. Jusqu'ici, le code n'avait aucun moyen de conserver des valeurs d'un chargement de page à l'autre.
Cet article présente localStorage, qui enregistre des valeurs dans le navigateur, et les chaînes JSON qui servent à enregistrer des tableaux et des objets.
Garder des valeurs après la fermeture de la page — setItem et getItem
Un site d'actualités veut retenir la taille de police choisie par l'utilisateur pour la réutiliser à sa prochaine visite. Même si tu la mets dans une variable, comme const fontSize = "large";, les variables disparaissent quand la page est rechargée ou fermée : la page ouverte la fois suivante ne peut donc pas la lire.
localStorage (un espace de stockage clé-valeur fourni par le navigateur) enregistre une valeur avec setItem(clé, valeur), la relit avec getItem(clé) et la supprime avec removeItem(clé).
Chaque origine (la partie de l'URL qui précède le chemin : https://news.example dans https://news.example/settings) a son propre stockage : les pages d'une même origine lisent et écrivent les mêmes valeurs.
// Si une valeur d'une exécution précédente est encore enregistrée, on la supprime pour repartir de zéro
localStorage.removeItem("fontSize");
// Enregistrer quand l'utilisateur passe la taille de police à large
localStorage.setItem("fontSize", "large");
// À l'ouverture de la page, lire la valeur enregistrée et l'utiliser
const fontSize = localStorage.getItem("fontSize");
console.log(fontSize); // large
// Enregistrer sous la même clé remplace la valeur précédente
localStorage.setItem("fontSize", "small");
console.log(localStorage.getItem("fontSize")); // small
- Les pages et onglets de cette origine partagent un seul localStorage
"fontSize"→"small"(remplacée en enregistrant sous la même clé)- Reste après la fermeture ou le rechargement de la page
- Les variables comme
const fontSize - Les variables sont recréées au rechargement
- A son propre localStorage
- Ne peut pas lire le
"fontSize"enregistré par news.example
Si tu lis avec getItem à l'ouverture de la page et que tu écris avec setItem quand l'utilisateur change le réglage, la page garde la même taille de police même après un rechargement. Les valeurs enregistrées restent jusqu'à ce que le code de la page les supprime ou que l'utilisateur les efface dans les paramètres du navigateur.
Les valeurs enregistrées persistent d'une exécution à l'autre
La console des exercices exécute tous les exercices JavaScript du site sur la même origine : ils partagent donc un seul localStorage, dont le contenu reste même si tu rouvres la page. Pour que des valeurs enregistrées lors d'exécutions précédentes ne se mêlent pas à tes résultats, les exercices commencent par supprimer avec removeItem les clés qu'ils utilisent.
Enregistrer des tableaux et des objets — JSON.stringify
Un site de réservation de voyages garde dans un tableau les hôtels qu'un utilisateur a mis en favoris, et veut les réafficher à sa prochaine visite. Passer le tableau tel quel à setItem ne provoque pas d'erreur, mais la valeur relue ne contient ni les identifiants des hôtels ni leurs noms.
setItem convertit en chaîne la valeur que tu lui passes avant de l'enregistrer. Transforme les tableaux et les objets en chaînes JSON avec JSON.stringify avant de les enregistrer, et reconvertis la chaîne relue en tableau ou en objet avec JSON.parse.
// Si une valeur d'une exécution précédente est encore enregistrée, on commence par la supprimer
localStorage.removeItem("favoriteHotels");
const favoriteHotels = [{ id: "H-101", name: "Hôtel du Port" }, { id: "H-204", name: "Hôtel de la Gare" }];
// Passé tel quel, le tableau est converti en chaîne au moment de l'enregistrement
localStorage.setItem("favoriteHotels", favoriteHotels);
console.log(localStorage.getItem("favoriteHotels")); // [object Object],[object Object]
// Le convertir en chaîne JSON avant de l'enregistrer
localStorage.setItem("favoriteHotels", JSON.stringify(favoriteHotels));
const saved = localStorage.getItem("favoriteHotels");
console.log(saved); // [{"id":"H-101","name":"Hôtel du Port"},{"id":"H-204","name":"Hôtel de la Gare"}]
// Reconvertir la chaîne relue en tableau avant de l'utiliser
const restored = JSON.parse(saved);
console.log(restored[1].name); // Hôtel de la Gare
Les nombres et les booléens sont eux aussi convertis en chaînes, sans le moindre message d'erreur : tu ne t'en rends compte que lorsqu'un calcul ou un test if sur la valeur relue donne un mauvais résultat. Le tableau ci-dessous indique, pour chaque valeur passée à setItem, la chaîne enregistrée, ce qui se passe à la relecture et la façon d'y remédier.
| Valeur passée à setItem | Chaîne stockée | À la relecture (solution) |
|---|---|---|
| Le nombre 20 | "20" | "20" + 1 donne "201" (Number) |
| Le booléen false | "false" | Vrai dans un if (JSON.parse) |
| Tableau ["A-1", "B-2"] | "A-1,B-2" | Une seule chaîne, plus un tableau |
Lire une clé non enregistrée — le null de getItem
Sur un site de recettes, les identifiants des recettes consultées sont enregistrés comme historique, et la page en affiche le nombre à l'ouverture. Un nouveau visiteur, ou quelqu'un qui a effacé son historique, n'a rien d'enregistré : si tu lis le length du résultat de JSON.parse en supposant qu'un historique existe, cette ligne lève une TypeError.
Quand tu passes à getItem une clé non enregistrée, il renvoie null, et non undefined. Si tu écris JSON.parse(localStorage.getItem(clé)) ?? [], un tableau vide n'est utilisé que lorsque rien n'est enregistré.
// Lire l'historique de consultation. Si rien n'est enregistré, utiliser un tableau vide
function loadHistory() {
return JSON.parse(localStorage.getItem("viewHistory")) ?? [];
}
// Première visite — rien n'est enregistré, donc getItem renvoie null
localStorage.removeItem("viewHistory");
console.log(localStorage.getItem("viewHistory")); // null
console.log(loadHistory().length); // 0
// Avec un historique enregistré — la chaîne redevient un tableau
localStorage.setItem("viewHistory", JSON.stringify(["R-12", "R-30"]));
console.log(loadHistory().length); // 2
// Après removeItem — de nouveau null
localStorage.removeItem("viewHistory");
console.log(loadHistory().length); // 0
Si tu regroupes la lecture dans une fonction, le code appelant peut traiter le résultat comme un tableau sans vérifier null, même après un removeItem à la déconnexion. removeItem ne lève pas d'erreur même pour une clé non enregistrée : inutile, donc, de vérifier qu'il y a quelque chose avant de supprimer.
Retrouver le panier après un rechargement — fonctions d'enregistrement et de chargement
Dans une boutique en ligne, le panier doit garder son contenu quand la page est rechargée après l'ajout d'un article. Ajouter un article avec cart.push ne modifie que la variable : s'il manque la ligne d'enregistrement à un seul endroit, cet article disparaît au rechargement.
Regroupe l'enregistrement dans une fonction saveCart et le chargement dans une fonction loadCart, puis appelle la première juste après chaque modification du panier, et la seconde à l'ouverture de la page. setItem est synchrone (il termine l'enregistrement avant de passer à la ligne suivante) : contrairement à fetch, tu peux lire la valeur enregistrée dès la ligne suivante, sans await.
localStorage.removeItem("cart"); // Si un panier d'une exécution précédente est encore enregistré, on le supprime
// Enregistrer le panier sous forme de chaîne JSON. Pas besoin d'await
function saveCart(cart) {
localStorage.setItem("cart", JSON.stringify(cart));
}
// Reconvertir le panier enregistré en tableau. Si rien n'est enregistré, renvoyer un panier vide
function loadCart() {
return JSON.parse(localStorage.getItem("cart")) ?? [];
}
// Charger à l'ouverture de la page, et enregistrer après l'ajout d'un article
const cart = loadCart();
cart.push({ id: "K-310", qty: 1 });
saveCart(cart);
// Au lieu de recharger, on relit la chaîne enregistrée sans utiliser la variable cart
const reloaded = loadCart();
console.log(reloaded.length, reloaded[0].id); // 1 K-310
Si tu regroupes tout ce qui modifie le panier dans une fonction qui appelle saveCart à la fin, tu n'as plus à écrire l'enregistrement à chaque appel, et tu ne peux plus l'oublier. Le chargement est lui aussi regroupé dans loadCart : il n'y a donc aucun endroit où oublier ?? [].
setItem lève une exception quand le stockage est plein
Dans Chrome, une origine peut stocker environ 5,24 millions de caractères, clés et valeurs comprises. Au-delà, setItem lève une QuotaExceededError et la valeur n'est pas enregistrée. Les lectures et écritures sont synchrones : la page cesse aussi de répondre pendant l'enregistrement d'une grosse valeur. Réserve localStorage aux petites valeurs, comme un panier ou des réglages.
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Après localStorage.setItem("darkMode", false), que se passe-t-il si tu utilises la valeur relue comme condition d'un if ?
Question 3Si tu recharges après cart.push(book) sans appeler saveCart, que renvoie loadCart() ?