Séance 12 — JSON et les erreurs
Sauvegarder des données, et survivre aux imprévus
- Transformer un objet en texte et l’inverse
- Sauvegarder des données dans le navigateur
- Attraper une erreur avec
try/catchau lieu de planter
1. Le problème du transport
Vos objets vivent dans la mémoire du navigateur. Rechargez la page : tout disparaît.
Pour sauvegarder des données, ou pour les envoyer à travers le réseau, il faut les transformer en texte. Car un fichier, un message réseau, une base de données : tout ça ne sait manipuler que du texte.
Le format universel pour faire ça s’appelle JSON (JavaScript Object Notation).
// Un objet JavaScript (vivant en mémoire)
const etudiant = { prenom: "Camille", age: 19 };
// Le même, en JSON (du texte)
'{"prenom":"Camille","age":19}'JSON est le format d’échange du web. Quand votre application météo affiche la température, quand Instagram charge des photos, quand vous consultez un horaire de train : du JSON circule.
Ce que vous apprenez ici sert partout, dans tous les langages.
2. Les deux fonctions
const etudiant = { prenom: "Camille", age: 19 };
// Objet → texte
const texte = JSON.stringify(etudiant);
console.log(texte); // {"prenom":"Camille","age":19}
console.log(typeof texte); // "string"
// Texte → objet
const retour = JSON.parse(texte);
console.log(retour.prenom); // "Camille"
console.log(typeof retour); // "object"| Fonction | Sens | Direction |
|---|---|---|
JSON.stringify(objet) |
transforme en chaîne | objet → texte |
JSON.parse(texte) |
analyse | texte → objet |
stringify contient string : il fabrique une chaîne. parse veut dire « analyser » : il lit une chaîne pour en tirer un objet.
Ça se ressemble beaucoup, mais les règles sont plus strictes.
{
"prenom": "Camille",
"age": 19,
"notes": [12, 15]
}| Règle JSON | En JavaScript |
|---|---|
Les noms sont entre "…" |
Facultatif |
| Guillemets doubles uniquement | '…' accepté |
| Pas de virgule après le dernier élément | Tolérée |
| Pas de commentaires | // accepté |
| Pas de fonctions | Autorisées |
Ces différences sont la cause n°1 des erreurs de JSON.parse.
Exercice 12.1
const config = { theme: "sombre", taille: 14, notifications: true };- Transformez-la en JSON et affichez le texte
- Reconstruisez un objet à partir de ce texte
- Affichez
typeofà chaque étape
app.js
const config = { theme: "sombre", taille: 14, notifications: true };
console.log(typeof config); // "object"
const texte = JSON.stringify(config);
console.log(texte); // {"theme":"sombre","taille":14,"notifications":true}
console.log(typeof texte); // "string"
const retour = JSON.parse(texte);
console.log(retour.theme); // "sombre"
console.log(typeof retour); // "object"Astuce lisibilité : JSON.stringify(config, null, 2) produit un JSON indenté sur plusieurs lignes, bien plus agréable à lire dans la console.
3. Sauvegarder pour de vrai : localStorage
Le navigateur offre un petit coffre-fort par site : localStorage. Il survit à la fermeture du navigateur.
localStorage.setItem("cle", "une valeur"); // écrire
const v = localStorage.getItem("cle"); // lire
localStorage.removeItem("cle"); // effacerlocalStorage ne stocke que du TEXTE
D’où l’obligation de passer par JSON :
// Sauvegarder un tableau
localStorage.setItem("taches", JSON.stringify(taches));
// Le relire
const taches = JSON.parse(localStorage.getItem("taches"));Si vous oubliez JSON.stringify, le navigateur enregistre bêtement "[object Object]" et vos données sont perdues.
localStorage
Tout code JavaScript de la page peut le lire. On n’y met donc jamais :
- de mot de passe
- de jeton de connexion
- de donnée personnelle sensible
C’est fait pour des préférences et des brouillons : thème choisi, liste de courses, panier en cours.
Étape 1 — La liste de tâches qui survit
Reprenez la liste de tâches de la séance 10, et ajoutez la persistance.
taches.js
const CLE = "mes-taches";
let taches = [];
function sauvegarder() {
localStorage.setItem(CLE, JSON.stringify(taches));
}
function charger() {
const texte = localStorage.getItem(CLE);
if (texte === null) {
taches = []; // première visite : rien de sauvegardé
return;
}
taches = JSON.parse(texte);
}
function afficher() {
liste.innerHTML = "";
for (const tache of taches) {
const li = document.createElement("li");
li.textContent = tache;
liste.appendChild(li);
}
compteur.textContent = `${taches.length} tâche(s)`;
}
ajoutForm.addEventListener("submit", (event) => {
event.preventDefault();
const texte = champ.value.trim();
if (texte === "") {
erreur.textContent = "La tâche ne peut pas être vide.";
return;
}
erreur.textContent = "";
taches.push(texte);
champ.value = "";
sauvegarder(); // ← la nouveauté
afficher();
});
charger();
afficher();Fermez complètement le navigateur, rouvrez la page : vos tâches sont encore là. 🎉
Dans l’inspecteur du navigateur, onglet Application (Chrome) ou Stockage (Firefox) → Local Storage. Vous y voyez vos clés et leurs valeurs, et vous pouvez les supprimer à la main pour tester.
4. Quand ça tourne mal : les erreurs
Ajoutez ceci dans la console du navigateur et rechargez la page :
localStorage.setItem("mes-taches", "ceci n'est pas du JSON");La page plante. La console affiche du rouge, et plus rien ne fonctionne.
JavaScript arrête tout, immédiatement. Toutes les lignes qui suivaient ne sont pas exécutées — d’où la page figée.
On dit que le programme lève une exception.
try / catch
try {
// le code qui pourrait mal tourner
taches = JSON.parse(texte);
} catch (erreur) {
// ce qu'on fait SI ça a mal tourné
console.log("Données illisibles, on repart de zéro.");
taches = [];
}try { ESSAIE ceci
…
} catch (e) { SI ÇA CASSE, fais plutôt ça
… (e contient la description du problème)
}
try / catch ne répare pas le problème : il empêche l’accident d’être fatal. Le programme continue, avec un comportement de secours.
Sans lui, la moindre donnée corrompue rend toute votre page inutilisable.
Étape 2 — Une fonction charger qui résiste
taches.js
function charger() {
const texte = localStorage.getItem(CLE);
if (texte === null) {
taches = [];
return;
}
try {
taches = JSON.parse(texte);
} catch (erreur) {
console.log("Sauvegarde corrompue :", erreur.message);
taches = [];
localStorage.removeItem(CLE); // on nettoie
}
}Refaites le test : mettez n’importe quoi dans localStorage, rechargez. La page fonctionne quand même, en repartant d’une liste vide.
try
try {
// 200 lignes
} catch (e) {
console.log("erreur"); // ❌ on ne sait plus ce qui a cassé
}try doit encadrer le minimum : l’instruction précise qui peut échouer. Sinon vous masquez vos propres bugs et le débogage devient impossible.
5. Déclencher soi-même une erreur
On peut refuser une situation avec throw :
function racine(n) {
if (n < 0) {
throw new Error("Impossible : nombre négatif");
}
return Math.sqrt(n);
}Et l’attraper à l’utilisation :
try {
console.log(racine(-4));
} catch (erreur) {
console.log(erreur.message); // Impossible : nombre négatif
}throw ou return false : lequel choisir ?
return false(ounull) quand l’échec est normal et attendu : un retrait refusé faute de solde, un formulaire mal rempli.throwquand la situation est anormale et ne devrait jamais arriver : un fichier illisible, une donnée corrompue, un paramètre absurde.
Dans les deux cas, on ne laisse jamais le programme continuer avec une valeur fausse. C’est ça, la fiabilité.
Exercice 12.2 — Prédire
Qu’affiche ce programme, et dans quel ordre ?
console.log("A");
try {
console.log("B");
JSON.parse("{pas du json}");
console.log("C");
} catch (e) {
console.log("D");
}
console.log("E");A
B
D
E
C ne s’affiche jamais. Dès que JSON.parse échoue, JavaScript saute directement au bloc catch : tout ce qui restait dans le try est abandonné.
Et E s’affiche bien : grâce au catch, le programme reprend son cours normal après le bloc. Sans try/catch, ni D ni E n’auraient été affichés.
6. À toi de jouer
Exercice 12.3 — Repérer le JSON invalide
Lesquels de ces textes JSON.parse accepte-t-il ?
a) {"nom": "Camille", "age": 19}
b) {'nom': 'Camille'}
c) {nom: "Camille"}
d) {"nom": "Camille",}
e) [1, 2, 3]
f) "juste du texte"
| Valide ? | Pourquoi | |
|---|---|---|
| a) | ✅ | Parfait |
| b) | ❌ | Guillemets simples : JSON exige des doubles |
| c) | ❌ | Le nom de propriété doit être entre guillemets |
| d) | ❌ | Virgule en trop avant } |
| e) | ✅ | Un tableau est du JSON valide |
| f) | ✅ | Une chaîne seule aussi (avec ses guillemets) |
À retenir : JSON ne contient pas forcément un objet. Un tableau, un nombre, une chaîne sont du JSON valide.
Exercice 12.4 — Une fonction de lecture sûre
Écrivez lireJSON(texte, valeurParDefaut) qui renvoie l’objet correspondant au texte, ou valeurParDefaut si le texte n’est pas du JSON valide.
console.log(lireJSON('{"a":1}', {})); // { a: 1 }
console.log(lireJSON("n'importe quoi", {})); // {}
console.log(lireJSON(null, [])); // []app.js
function lireJSON(texte, valeurParDefaut) {
if (texte === null || texte === "") {
return valeurParDefaut;
}
try {
return JSON.parse(texte);
} catch (erreur) {
console.log("JSON invalide :", erreur.message);
return valeurParDefaut;
}
}Deux protections successives :
- Le
ifgère le cas « rien à lire » — ce n’est pas une erreur, c’est normal (première visite). - Le
try/catchgère le cas « il y a quelque chose, mais c’est cassé ».
On peut mettre un return à l’intérieur d’un try : la fonction rend la valeur et sort normalement.
Exercice 12.5 — Le carnet de notes qui se souvient 💾
Reprenez le répertoire de contacts de la séance 11 et rendez-le persistant.
Contraintes :
- Après chaque ajout, sauvegarder dans
localStorage - Au chargement, restaurer la liste — en reconstruisant de vrais objets
Contact, pas de simples objets plats - Toute la lecture protégée par
try/catch - Un bouton
Tout effacerqui vide la liste et le stockage
JSON.parse renvoie des objets ordinaires. Il ne sait rien de vos classes :
const c = JSON.parse('{"nom":"Camille","email":"c@x.fr"}');
c.resume(); // ❌ ERREUR : resume is not a functionLes données sont là, mais les méthodes ont disparu au passage par le texte. Il faut donc recréer les objets avec new.
contacts.js
class Contact {
constructor(nom, email, telephone) {
this.nom = nom;
this.email = email;
this.telephone = telephone;
}
resume() {
return `${this.nom} — ${this.email}`;
}
}
const CLE = "mes-contacts";
let contacts = [];
function sauvegarder() {
localStorage.setItem(CLE, JSON.stringify(contacts));
}
function charger() {
const texte = localStorage.getItem(CLE);
if (texte === null) {
contacts = [];
return;
}
try {
const bruts = JSON.parse(texte);
contacts = [];
// on RECONSTRUIT de vrais Contact, pour retrouver les méthodes
for (const brut of bruts) {
contacts.push(new Contact(brut.nom, brut.email, brut.telephone));
}
} catch (erreur) {
console.log("Sauvegarde illisible :", erreur.message);
contacts = [];
localStorage.removeItem(CLE);
}
}
function afficher() {
liste.innerHTML = "";
for (const contact of contacts) {
const li = document.createElement("li");
li.textContent = contact.resume(); // ← ne marche que si c'est un vrai Contact
liste.appendChild(li);
}
compteur.textContent = `${contacts.length} contact(s) enregistré(s)`;
}
formulaire.addEventListener("submit", (event) => {
event.preventDefault();
const nom = nomEl.value.trim();
const email = emailEl.value.trim();
if (nom === "") {
erreur.textContent = "Le nom est obligatoire.";
return;
}
if (!email.includes("@")) {
erreur.textContent = "L'email doit contenir un @.";
return;
}
erreur.textContent = "";
contacts.push(new Contact(nom, email, telEl.value.trim()));
formulaire.reset();
sauvegarder();
afficher();
});
document.querySelector("#effacer").addEventListener("click", () => {
contacts = [];
localStorage.removeItem(CLE);
afficher();
});
charger();
afficher();La boucle de reconstruction est le cœur de l’exercice. Elle illustre une vérité générale : le JSON transporte des données, jamais du comportement.
7. Fiche mémo
Les deux conversions
const texte = JSON.stringify(objet); // objet → texte
const objet = JSON.parse(texte); // texte → objetSauvegarder
localStorage.setItem("cle", JSON.stringify(donnees));
const donnees = JSON.parse(localStorage.getItem("cle"));
localStorage.removeItem("cle");getItem renvoie null si la clé n’existe pas → toujours tester.
Se protéger
try {
donnees = JSON.parse(texte);
} catch (erreur) {
console.log(erreur.message);
donnees = [];
}Refuser une situation
if (n < 0) {
throw new Error("message clair");
}Les 3 pièges
localStoragene stocke que du texte →JSON.stringifyobligatoire- JSON exige des guillemets doubles et pas de virgule finale
JSON.parserend des objets sans méthodes → reconstruire avecnew