Disons que nous avons un objet complexe et que nous aimerions le convertir en chaîne, l'envoyer sur un réseau ou simplement le sortir à des fins de journalisation.
Naturellement, une telle chaîne doit inclure toutes les propriétés importantes.
Nous pourrions implémenter la conversion comme ceci :
laissez l'utilisateur = { nom : "Jean", âge : 30 ans, versChaîne() { return `{name : "${this.name}", age : ${this.age}}` ; } } ; alerte (utilisateur); // {nom : "Jean", âge : 30}
…Mais au cours du processus de développement, de nouvelles propriétés sont ajoutées, les anciennes propriétés sont renommées et supprimées. Mettre à jour ce toString
à chaque fois peut devenir pénible. Nous pourrions essayer d'y parcourir des propriétés, mais que se passe-t-il si l'objet est complexe et contient des objets imbriqués dans des propriétés ? Nous devrons également mettre en œuvre leur conversion.
Heureusement, il n'est pas nécessaire d'écrire le code pour gérer tout cela. La tâche a déjà été résolue.
Le JSON (JavaScript Object Notation) est un format général pour représenter des valeurs et des objets. Il est décrit comme dans la norme RFC 4627. Initialement, il a été conçu pour JavaScript, mais de nombreux autres langages disposent également de bibliothèques pour le gérer. Il est donc facile d'utiliser JSON pour l'échange de données lorsque le client utilise JavaScript et que le serveur est écrit en Ruby/PHP/Java/Whatever.
JavaScript fournit des méthodes :
JSON.stringify
pour convertir des objets en JSON.
JSON.parse
pour reconvertir JSON en objet.
Par exemple, ici nous JSON.stringify
un étudiant :
laissez étudiant = { nom : « Jean », âge : 30 ans, isAdmin : faux, cours : ['html', 'css', 'js'], conjoint : nul } ; let json = JSON.stringify(étudiant); alert(type de json); // nous avons une chaîne ! alerte(json); /* Objet codé en JSON : { "nom": "Jean", "âge": 30, "isAdmin": faux, "cours": ["html", "css", "js"], "conjoint": nul } */
La méthode JSON.stringify(student)
prend l'objet et le convertit en chaîne.
La chaîne json
résultante est appelée un objet codé JSON , sérialisé , chaîne ou marshallé . Nous sommes prêts à l'envoyer par câble ou à le placer dans un simple magasin de données.
Veuillez noter qu'un objet codé en JSON présente plusieurs différences importantes par rapport au littéral d'objet :
Les chaînes utilisent des guillemets doubles. Pas de guillemets simples ni de backticks dans JSON. Ainsi, 'John'
devient "John"
.
Les noms de propriétés d'objet sont également entre guillemets. C'est obligatoire. Donc age:30
devient "age":30
.
JSON.stringify
peut également être appliqué aux primitives.
JSON prend en charge les types de données suivants :
Objets { ... }
Tableaux [ ... ]
Primitives :
des cordes,
Nombres,
valeurs booléennes true/false
,
null
.
Par exemple:
// un nombre en JSON n'est qu'un nombre alerte( JSON.stringify(1) ) // 1 // une chaîne en JSON est toujours une chaîne, mais entre guillemets alerte( JSON.stringify('test') ) // "test" alerte( JSON.stringify(true) ); // vrai alerte( JSON.stringify([1, 2, 3]) ); // [1,2,3]
JSON est une spécification indépendante du langage et des données uniquement, donc certaines propriétés d'objet spécifiques à JavaScript sont ignorées par JSON.stringify
.
À savoir:
Propriétés de fonction (méthodes).
Clés et valeurs symboliques.
Propriétés qui stockent undefined
.
laissez l'utilisateur = { sayHi() { // ignoré alerte("Bonjour"); }, [Symbole("id")] : 123, // ignoré quelque chose : non défini // ignoré } ; alerte( JSON.stringify(utilisateur) ); // {} (objet vide)
Habituellement, ça va. Si ce n’est pas ce que nous voulons, nous verrons bientôt comment personnaliser le processus.
L'avantage est que les objets imbriqués sont pris en charge et convertis automatiquement.
Par exemple:
laissez-vous rencontrer = { titre : "Conférence", chambre: { numéro : 23, participants : ["john", "ann"] } } ; alerte( JSON.stringify(meetup) ); /* La structure entière est stringifiée : { "title": "Conférence", "room":{"number":23,"participants":["john","ann"]}, } */
La limitation importante : il ne doit pas y avoir de références circulaires.
Par exemple:
laisser de la place = { numéro : 23 } ; laissez-vous rencontrer = { titre : "Conférence", participants : ["john", "ann"] } ; meetup.place = salle ; // salle de références meetup room.occupiedBy = rencontre ; // rencontre avec les références des salles JSON.stringify(rencontre); // Erreur : Conversion de la structure circulaire en JSON
Ici, la conversion échoue, à cause d'une référence circulaire : room.occupiedBy
fait référence à meetup
et meetup.place
fait référence room
:
La syntaxe complète de JSON.stringify
est :
let json = JSON.stringify(value[, replacer, space])
valeur
Une valeur à coder.
remplaçant
Tableau de propriétés à encoder ou une function(key, value)
.
espace
Quantité d'espace à utiliser pour le formatage
La plupart du temps, JSON.stringify
est utilisé uniquement avec le premier argument. Mais si nous devons affiner le processus de remplacement, comme filtrer les références circulaires, nous pouvons utiliser le deuxième argument de JSON.stringify
.
Si on lui passe un tableau de propriétés, seules ces propriétés seront codées.
Par exemple:
laisser de la place = { numéro : 23 } ; laissez-vous rencontrer = { titre : "Conférence", participants : [{nom : "John"}, {nom : "Alice"}], lieu : salle // salle de références de rencontre } ; room.occupiedBy = rencontre ; // rencontre avec les références des salles alert( JSON.stringify(meetup, ['title', 'participants']) ); // {"title":"Conférence","participants":[{},{}]}
Ici, nous sommes probablement trop stricts. La liste des propriétés est appliquée à l'ensemble de la structure de l'objet. Les objets des participants
sont donc vides, car name
n'est pas dans la liste.
Incluons dans la liste toutes les propriétés sauf room.occupiedBy
qui provoqueraient la référence circulaire :
laisser de la place = { numéro : 23 } ; laissez-vous rencontrer = { titre : "Conférence", participants : [{nom : "John"}, {nom : "Alice"}], lieu : salle // salle de références de rencontre } ; room.occupiedBy = rencontre ; // rencontre avec les références des salles alert( JSON.stringify(meetup, ['titre', 'participants', 'lieu', 'nom', 'numéro']) ); /* { "title": "Conférence", "participants":[{"name":"John"},{"name":"Alice"}], "lieu":{"numéro":23} } */
Désormais, tout sauf occupiedBy
est sérialisé. Mais la liste des propriétés est assez longue.
Heureusement, nous pouvons utiliser une fonction au lieu d'un tableau comme replacer
.
La fonction sera appelée pour chaque paire (key, value)
et devra renvoyer la valeur « remplacée », qui sera utilisée à la place de celle d'origine. Ou undefined
si la valeur doit être ignorée.
Dans notre cas, nous pouvons renvoyer value
« telle quelle » pour tout sauf occupiedBy
. Pour ignorer occupiedBy
, le code ci-dessous renvoie undefined
:
laisser de la place = { numéro : 23 } ; laissez-vous rencontrer = { titre : "Conférence", participants : [{nom : "John"}, {nom : "Alice"}], lieu : salle // salle de références de rencontre } ; room.occupiedBy = rencontre ; // rencontre avec les références des salles alert( JSON.stringify(meetup, function replacer(clé, valeur) { alert(`${key} : ${value}`); return (key == 'occupiedBy') ? non défini : valeur ; })); /* Clé : paires de valeurs qui viennent en remplacement : : [objet Objet] titre : Conférence participants : [objet Objet],[objet Objet] 0 : [objet Objet] nom : Jean 1 : [objet Objet] prénom : Alice lieu : [objet Objet] numéro : 23 occupéBy : [objet Objet] */
Veuillez noter que la fonction replacer
récupère chaque paire clé/valeur, y compris les objets imbriqués et les éléments du tableau. Il est appliqué de manière récursive. La valeur de this
replacer
interne est l'objet qui contient la propriété actuelle.
Le premier appel est spécial. Il est réalisé à l'aide d'un « objet wrapper » spécial : {"": meetup}
. En d’autres termes, la première paire (key, value)
a une clé vide et la valeur correspond à l’objet cible dans son ensemble. C'est pourquoi la première ligne est ":[object Object]"
dans l'exemple ci-dessus.
L'idée est de fournir autant de puissance que possible au replacer
: il a la possibilité d'analyser et de remplacer/ignorer même l'objet entier si nécessaire.
Le troisième argument de JSON.stringify(value, replacer, space)
est le nombre d'espaces à utiliser pour un joli formatage.
Auparavant, tous les objets stringifiés n'avaient ni retrait ni espace supplémentaire. C'est très bien si nous voulons envoyer un objet sur un réseau. L'argument space
est utilisé exclusivement pour une belle sortie.
Ici space = 2
indique à JavaScript d'afficher les objets imbriqués sur plusieurs lignes, avec une indentation de 2 espaces à l'intérieur d'un objet :
laissez l'utilisateur = { nom : "Jean", âge : 25 ans, rôles : { isAdmin : faux, isEditor : vrai } } ; alert(JSON.stringify(user, null, 2)); /* retrait de deux espaces : { "nom": "Jean", "âge": 25, "rôles": { "isAdmin": faux, "isEditor": vrai } } */ /* pour JSON.stringify(user, null, 4) le résultat serait plus indenté : { "nom": "Jean", "âge": 25, "rôles": { "isAdmin": faux, "isEditor": vrai } } */
Le troisième argument peut également être une chaîne. Dans ce cas, la chaîne est utilisée pour l'indentation au lieu d'un certain nombre d'espaces.
Le paramètre space
est utilisé uniquement à des fins de journalisation et de belle sortie.
Comme toString
pour la conversion de chaîne, un objet peut fournir la méthode toJSON
pour la conversion en JSON. JSON.stringify
l'appelle automatiquement s'il est disponible.
Par exemple:
laisser de la place = { numéro : 23 } ; laissez-vous rencontrer = { titre : "Conférence", date : nouvelle Date(Date.UTC(2017, 0, 1)), chambre } ; alerte( JSON.stringify(meetup) ); /* { "title": "Conférence", "date": "2017-01-01T00: 00: 00.000Z", // (1) "chambre": {"numéro":23} // (2) } */
Ici, nous pouvons voir que date
(1)
est devenue une chaîne. En effet, toutes les dates ont une méthode toJSON
intégrée qui renvoie ce type de chaîne.
Ajoutons maintenant un toJSON
personnalisé pour notre room
d'objets (2)
:
laisser de la place = { numéro : 23, versJSON() { renvoie ce.numéro ; } } ; laissez-vous rencontrer = { titre : "Conférence", chambre } ; alert( JSON.stringify(room) ); // 23 alerte( JSON.stringify(meetup) ); /* { "title": "Conférence", "chambre": 23 } */
Comme nous pouvons le voir, toJSON
est utilisé à la fois pour l'appel direct JSON.stringify(room)
et lorsque room
est imbriqué dans un autre objet codé.
Pour décoder une chaîne JSON, nous avons besoin d'une autre méthode nommée JSON.parse.
La syntaxe :
let value = JSON.parse(str[, reviver]);
str
Chaîne JSON à analyser.
raviveur
Fonction facultative (clé, valeur) qui sera appelée pour chaque paire (key, value)
et pourra transformer la valeur.
Par exemple:
// tableau stringifié soit les nombres = "[0, 1, 2, 3]" ; nombres = JSON.parse(nombres); alerte( numéros[1] ); // 1
Ou pour les objets imbriqués :
let userData = '{ "name": "John", "age": 35, "isAdmin": false, "friends": [0,1,2,3] }'; laissez l'utilisateur = JSON.parse(userData); alert( user.friends[1] ); // 1
Le JSON peut être aussi complexe que nécessaire, les objets et tableaux peuvent inclure d'autres objets et tableaux. Mais ils doivent obéir au même format JSON.
Voici les erreurs typiques du JSON écrit à la main (nous devons parfois l'écrire à des fins de débogage) :
laissez json = `{ nom : "John", // erreur : nom de la propriété sans guillemets "nom": 'Smith', // erreur : guillemets simples dans la valeur (doit être double) 'isAdmin' : false // erreur : guillemets simples dans la clé (doit être double) "birthday": new Date(2000, 2, 3), // erreur : aucun "new" n'est autorisé, uniquement des valeurs nues "friends": [0,1,2,3] // ici tout va bien }`;
De plus, JSON ne prend pas en charge les commentaires. L'ajout d'un commentaire à JSON le rend invalide.
Il existe un autre format nommé JSON5, qui autorise les clés, commentaires, etc. sans guillemets. Mais il s'agit d'une bibliothèque autonome, qui n'est pas incluse dans la spécification du langage.
Le JSON standard est aussi strict non pas parce que ses développeurs sont paresseux, mais pour permettre des implémentations faciles, fiables et très rapides de l'algorithme d'analyse.
Imaginez, nous avons reçu un objet meetup
stringifié du serveur.
Cela ressemble à ceci :
// titre : (titre de la rencontre), date : (date de la rencontre) let str = '{"title":"Conférence","date":"2017-11-30T12:00:00.000Z"}';
…Et maintenant nous devons le désérialiser , pour le transformer en objet JavaScript.
Faisons-le en appelant JSON.parse
:
let str = '{"title":"Conférence","date":"2017-11-30T12:00:00.000Z"}'; laissez meetup = JSON.parse(str); alert( meetup.date.getDate() ); // Erreur!
Oups ! Une erreur !
La valeur de meetup.date
est une chaîne et non un objet Date
. Comment JSON.parse
pourrait-il savoir qu'il doit transformer cette chaîne en Date
?
Passons à JSON.parse
la fonction de relance comme deuxième argument, qui renvoie toutes les valeurs « telles quelles », mais date
deviendra une Date
:
let str = '{"title":"Conférence","date":"2017-11-30T12:00:00.000Z"}'; let meetup = JSON.parse(str, function(clé, valeur) { if (key == 'date') return new Date(value); valeur de retour ; }); alert( meetup.date.getDate() ); // fonctionne maintenant !
À propos, cela fonctionne également pour les objets imbriqués :
laissez planning = `{ "rencontres": [ {"title":"Conférence","date":"2017-11-30T12:00:00.000Z"}, {"title": "Anniversaire", "date": "2017-04-18T12:00:00.000Z"} ] }`; planning = JSON.parse(calendrier, fonction(clé, valeur) { if (key == 'date') return new Date(value); valeur de retour ; }); alert( planning.meetups[1].date.getDate() ); // travaux!
JSON est un format de données qui possède son propre standard indépendant et ses propres bibliothèques pour la plupart des langages de programmation.
JSON prend en charge les objets simples, les tableaux, les chaînes, les nombres, les booléens et null
.
JavaScript fournit les méthodes JSON.stringify pour sérialiser en JSON et JSON.parse pour lire à partir de JSON.
Les deux méthodes prennent en charge les fonctions de transformateur pour une lecture/écriture intelligente.
Si un objet doit toJSON
, alors il est appelé par JSON.stringify
.
importance : 5
Transformez l' user
en JSON, puis relisez-le dans une autre variable.
laissez l'utilisateur = { nom : « John Smith », âge : 35 ans } ;
laissez l'utilisateur = { nom : « John Smith », âge : 35 ans } ; laissez user2 = JSON.parse(JSON.stringify(user));
importance : 5
Dans des cas simples de références circulaires, nous pouvons exclure une propriété incriminée de la sérialisation par son nom.
Mais parfois, nous ne pouvons pas simplement utiliser le nom, car il peut être utilisé à la fois dans des références circulaires et dans des propriétés normales. Nous pouvons donc vérifier la propriété par sa valeur.
Écrivez une fonction replacer
pour tout chaîner, mais supprimez les propriétés qui font référence meetup
:
laisser de la place = { numéro : 23 } ; laissez-vous rencontrer = { titre : "Conférence", occupéBy : [{nom : "John"}, {nom : "Alice"}], lieu : chambre } ; // références circulaires room.occupiedBy = rencontre ; meetup.self = rencontre; alert( JSON.stringify(meetup, function replacer(clé, valeur) { /* votre code */ })); /* le résultat devrait être : { "title": "Conférence", "occupiedBy":[{"name":"John"},{"name":"Alice"}], "lieu":{"numéro":23} } */
laisser de la place = { numéro : 23 } ; laissez-vous rencontrer = { titre : "Conférence", occupéBy : [{nom : "John"}, {nom : "Alice"}], lieu : chambre } ; room.occupiedBy = rencontre ; meetup.self = rencontre; alert( JSON.stringify(meetup, function replacer(clé, valeur) { return (key != "" && value == meetup) ? non défini : valeur ; })); /* { "title": "Conférence", "occupiedBy":[{"name":"John"},{"name":"Alice"}], "lieu":{"numéro":23} } */
Ici, nous devons également tester key==""
pour exclure le premier appel où il est normal que value
soit meetup
.