Pewarta Proxy

📋 Server Request & Proxy Logs

Loading active proxy settings...
Developed by Khairul Adha (adhexa.id)
Mengambil log server...

⚙ Pengaturan Proxy Target

27 avril 2023

JSON methods, toJSON

Supposons que nous avons un objet complexe et que nous aimerions le convertir en chaĂźne, l’envoyer par le rĂ©seau ou simplement le rendre (l’output) Ă  des fins de journalisation.

Naturellement, une telle chaßne devrait inclure toutes les propriétés importantes.

Nous pourrions implémenter la conversion comme ceci :

let user = {
  name: "John",
  age: 30,

  toString() {
    return `{name: "${this.name}", age: ${this.age}}`;
  }
};

alert(user); // {name: "John", age: 30}


 Mais au cours du dĂ©veloppement, de nouvelles propriĂ©tĂ©s sont ajoutĂ©es, les anciennes propriĂ©tĂ©s sont renommĂ©es et supprimĂ©es. Mettre Ă  jour un tel toString Ă  chaque fois peut devenir pĂ©nible. Nous pourrions essayer de passer en boucle sur les propriĂ©tĂ©s qu’il contient, mais que se passe-t-il si l’objet est complexe et qu’il contient des objets imbriquĂ©s ? Nous aurions Ă©galement besoin de 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.

JSON.stringify

Le JSON (JavaScript Object Notation) est un format gĂ©nĂ©ral pour reprĂ©senter les valeurs et les objets. Il est dĂ©crit comme tel dans le standard RFC 4627. Initialement, il Ă©tait 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 sur Ruby/PHP/Java et bien d’autres.

JavaScript fournit des méthodes :

  • JSON.stringify pour convertir des objets en JSON.
  • JSON.parse pour reconvertir JSON en objet.

Par exemple, nous allons JSON.stringify un student (étudiant) :

let student = {
  name: 'John',
  age: 30,
  isAdmin: false,
  courses: ['html', 'css', 'js'],
  spouse: null
};

let json = JSON.stringify(student);

alert(typeof json); // nous avons une string !

alert(json);
/* Objet encodé en JSON :
{
  "name": "John",
  "age": 30,
  "isAdmin": false,
  "courses": ["html", "css", "js"],
  "spouse": null
}
*/

La mĂ©thode JSON.stringify(student) prend l’objet et le convertit en une chaĂźne.

La chaine json rĂ©sultante est appelĂ© un objet JSON-encoded ou serialized (sĂ©rialisĂ©) ou stringified ou marshalled. Nous sommes prĂȘts Ă  l’envoyer par le cĂąble ou Ă  le placer dans un simple stockage de donnĂ©es.

Veuillez noter qu’un objet JSON-encoded a plusieurs diffĂ©rences importantes par rapport au objet littĂ©ral :

  • Les chaĂźnes utilisent des guillemets doubles. Il n’y a pas de guillemets simples ni de backticks en JSON. Donc 'John' deviendra "John".
  • Les propriĂ©tĂ© d’objet sont Ă©galement en guillemets doubles. C’est obligatoire. Donc age:30 deviendra "age":30.

JSON.stringify peut aussi ĂȘtre appliquĂ© aux primitives.

JSON prend en charge les types de données suivants :

  • Objets { ... }
  • Tableaux [ ... ]
  • Primitives :
    • chaĂźnes,
    • nombres,
    • valeurs boolĂ©ennes true/false,
    • null.

Par exemple :

// un nombre en JSON est juste un nombre
alert( JSON.stringify(1) ) // 1

// une chaĂźne en JSON est toujours une chaĂźne, mais entre guillemets
alert( JSON.stringify('test') ) // "test"

alert( JSON.stringify(true) ); // true

alert( JSON.stringify([1, 2, 3]) ); // [1,2,3]

JSON est une spĂ©cification indĂ©pendante du langage et ne contenant que des donnĂ©es. Par consĂ©quent, 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.
let user = {
  sayHi() { // ignorée
    alert("Hello");
  },
  [Symbol("id")]: 123, // ignorée
  something: undefined // ignorée
};

alert( JSON.stringify(user) ); // {} (objet vide)

D’habitude ça va. Si ce n’est pas ce que nous souhaitons, nous verrons bientît comment personnaliser le processus.

Le grand avantage est que les objets imbriqués sont pris en charge et convertis automatiquement.

Par exemple :

let meetup = {
  title: "Conference",
  room: {
    number: 23,
    participants: ["john", "ann"]
  }
};

alert( JSON.stringify(meetup) );
/* La structure entiĂšre est stringified :
{
  "title":"Conference",
  "room":{"number":23,"participants":["john","ann"]},
}
*/

La limitation importante est qu’il ne doit pas y avoir de rĂ©fĂ©rences circulaires.

Par exemple :

let room = {
  number: 23
};

let meetup = {
  title: "Conference",
  participants: ["john", "ann"]
};

meetup.place = room;      // meetup references room
room.occupiedBy = meetup; // room references meetup

JSON.stringify(meetup); // Erreur: Conversion d'une structure circulaire en JSON

Ici, la conversion Ă©choue Ă  cause d’une rĂ©fĂ©rence circulaire : room.occupiedBy references meetup, et meetup.place references room :

Exclure et transformer : replacer

La syntaxe complĂšte de JSON.stringify est :

let json = JSON.stringify(value[, replacer, space])
Value
Une valeur Ă  encoder.
Replacer
Tableau de propriétés à encoder ou une fonction de mapping function(key, value).
Space
QuantitĂ© d’espace Ă  utiliser pour le formatage

La plupart du temps, JSON.stringify est utilisé avec le premier argument uniquement. Mais si nous devons affiner le processus de remplacement, préférez filtrer les références circulaires, nous pouvons utiliser le deuxiÚme argument de JSON.stringify.

Si nous lui passons un tableau de propriétés, seules ces propriétés seront encodées.

Par exemple :

let room = {
  number: 23
};

let meetup = {
  title: "Conference",
  participants: [{name: "John"}, {name: "Alice"}],
  place: room // meetup references room
};

room.occupiedBy = meetup; // room references meetup

alert( JSON.stringify(meetup, ['title', 'participants']) );
// {"title":"Conference","participants":[{},{}]}

Ici, nous sommes probablement trop strictes. La liste de propriĂ©tĂ©s est appliquĂ©e Ă  la structure entiĂšre de l’objet. Donc, les objets dans participants sont vides, parce que name n’est pas dans la liste.

Incluons dans la liste toutes les propriétés sauf room.occupiedBy qui provoquerait la référence circulaire :

let room = {
  number: 23
};

let meetup = {
  title: "Conference",
  participants: [{name: "John"}, {name: "Alice"}],
  place: room // meetup references room
};

room.occupiedBy = meetup; // room references meetup

alert( JSON.stringify(meetup, ['title', 'participants', 'place', 'name', 'number']) );
/*
{
  "title":"Conference",
  "participants":[{"name":"John"},{"name":"Alice"}],
  "place":{"number":23}
}
*/

Maintenant tout sauf occupiedBy est serialisé. 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 de (key, value) et devrait 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 retourner une value “en l’état” pour tout sauf occupiedBy. Pour ignorer occupiedBy, le code ci-dessous retourne undefined :

let room = {
  number: 23
};

let meetup = {
  title: "Conference",
  participants: [{name: "John"}, {name: "Alice"}],
  place: room // meetup references room
};

room.occupiedBy = meetup; // room references meetup

alert( JSON.stringify(meetup, function replacer(key, value) {
  alert(`${key}: ${value}`);
  return (key == 'occupiedBy') ? undefined : value;
}));

/* key:value pairs that come to replacer:
:             [object Object]
title:        Conference
participants: [object Object],[object Object]
0:            [object Object]
name:         John
1:            [object Object]
name:         Alice
place:        [object Object]
number:       23
occupiedBy:   [object Object]
*/

Veuillez noter que la fonction replacer rĂ©cupĂšre chaque paire clĂ©/valeur, y compris les objets imbriquĂ©s et les Ă©lĂ©ments de tableau. Il est appliquĂ© de maniĂšre rĂ©cursive. La valeur this dans replacer est l’objet qui contient la propriĂ©tĂ© actuelle.

Le premier appel est spĂ©cial. Il est fabriquĂ© en utilisant un “objet wrapper” spĂ©cial: {"": meetup}. En d’autres termes, la premiĂšre paire (key, value) a une clĂ© vide, et la valeur est 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 pour replacer que possible : il a une chance d’analyser et de remplacer/ignorer mĂȘme l’objet entier si nĂ©cessaire.

Formatage : space

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 pas d’indentation ni d’espace supplĂ©mentaire. C’est bien si nous voulons envoyer un objet sur un rĂ©seau. L’arguement space est utilisĂ© exclusivement pour une belle sortie.

Ici space = 2 indique Ă  JavaScript d’afficher des objets imbriquĂ©s sur plusieurs lignes, avec l’indentation de 2 espaces Ă  l’intĂ©rieur d’un objet :

let user = {
  name: "John",
  age: 25,
  roles: {
    isAdmin: false,
    isEditor: true
  }
};

alert(JSON.stringify(user, null, 2));
/* indentation de 2 espaces :
{
  "name": "John",
  "age": 25,
  "roles": {
    "isAdmin": false,
    "isEditor": true
  }
}
*/

/* pour JSON.stringify(user, null, 4) le résultat serait plus indenté :
{
    "name": "John",
    "age": 25,
    "roles": {
        "isAdmin": false,
        "isEditor": true
    }
}
*/

Le troisiĂšme argument peut Ă©galement ĂȘtre une chaĂźne de caractĂšres. Dans ce cas, la chaĂźne de caractĂšres 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 sortie agréable.

“toJSON” personnalisĂ©

Comme toString pour la conversion de chaßne, un objet peut fournir une méthode toJSON pour une conversion en JSON. JSON.stringify appelle automatiquement si il est disponible.

Par exemple :

let room = {
  number: 23
};

let meetup = {
  title: "Conference",
  date: new Date(Date.UTC(2017, 0, 1)),
  room
};

alert( JSON.stringify(meetup) );
/*
  {
    "title":"Conference",
    "date":"2017-01-01T00:00:00.000Z",  // (1)
    "room": {"number":23}               // (2)
  }
*/

Ici on peut voir que date (1) est devenu une chaĂźne. C’est parce que toutes les dates ont une mĂ©thode toJSON intĂ©grĂ©e qui retourne ce genre de chaĂźne.

Ajoutons maintenant un toJSON personnalisé pour notre objet room (2) :

let room = {
  number: 23,
  toJSON() {
    return this.number;
  }
};

let meetup = {
  title: "Conference",
  room
};

alert( JSON.stringify(room) ); // 23

alert( JSON.stringify(meetup) );
/*
  {
    "title":"Conference",
    "room": 23
  }
*/

Comme on peut le voir, toJSON est utilisĂ© Ă  la fois pour l’appel direct JSON.stringify(room) et quand room est imbriquĂ© dans un autre objet encodĂ©.

JSON.parse

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
La chaĂźne JSON Ă  parse.
reviver
Fonction optionnelle (clé, valeur) qui sera appelée pour chaque paire (key, value) et peut transformer la valeur.

Par exemple :

// stringified array
let numbers = "[0, 1, 2, 3]";

numbers = JSON.parse(numbers);

alert( numbers[1] ); // 1

Ou pour les objets imbriqués :

let userData = '{ "name": "John", "age": 35, "isAdmin": false, "friends": [0,1,2,3] }';

let user = JSON.parse(userData);

alert( user.friends[1] ); // 1

Le JSON peut ĂȘtre aussi complexe que nĂ©cessaire, les objets et les tableaux peuvent inclure d’autres objets et tableaux. Mais ils doivent obĂ©ir au mĂȘme format JSON.

Voici des erreurs typiques dans JSON Ă©crit Ă  la main (nous devons parfois l’écrire Ă  des fins de dĂ©bogage) :

let json = `{
  name: "John",                     // Erreur: nom de propriété sans guillemets
  "surname": 'Smith',               // Erreur: guillemets simples en valeur (doit ĂȘtre double)
  'isAdmin': false                  // Erreur: guillemets simples dans la clĂ© (doit ĂȘtre double)
  "birthday": new Date(2000, 2, 3), // Erreur: aucun "nouveau" n'est autorisé, seules les valeurs nues
  "friends": [0,1,2,3]              // Ici tout va bien
}`;

En outre, JSON ne prend pas en charge les commentaires. L’ajout d’un commentaire à JSON le rend invalide.

Il y a un autre format nommĂ© JSON5 qui autorise les clĂ©s non commentĂ©es, les commentaires, etc. Mais il s’agit d’une bibliothĂšque autonome, pas dans la spĂ©cification du langage.

Le JSON standard est trĂšs strict, non pas parce que ses dĂ©veloppeurs sont paresseux, mais pour permettre une implĂ©mentation facile, fiable et trĂšs rapide de l’algorithme de conversion.

Utiliser Reviver

Imaginez, nous avons un objet stringified meetup sur le serveur.

Cela ressemble à ça :

// title: (meetup title), date: (meetup date)
let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';


 Et maintenant, nous devons le deserialize, pour le retourner en objet JavaScript.

Faisons-le en appelant JSON.parse :

let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';

let meetup = JSON.parse(str);

alert( meetup.date.getDate() ); // Error!

Whoops ! Une erreur !

La valeur de meetup.date est une chaüne et non un objet Date. Comment JSON.parse pourrait-il savoir qu’il devrait transformer cette chaüne en Date ?

Passons Ă  JSON.parse la fonction de rĂ©activation en tant que second argument, qui renvoie toutes les valeurs “en l’état”, mais date deviendra une Date :

let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}';

let meetup = JSON.parse(str, function(key, value) {
  if (key == 'date') return new Date(value);
  return value;
});

alert( meetup.date.getDate() ); // ça fonctionne maintenant !

À propos, cela fonctionne aussi pour les objets imbriquĂ©s :

let schedule = `{
  "meetups": [
    {"title":"Conference","date":"2017-11-30T12:00:00.000Z"},
    {"title":"Birthday","date":"2017-04-18T12:00:00.000Z"}
  ]
}`;

schedule = JSON.parse(schedule, function(key, value) {
  if (key == 'date') return new Date(value);
  return value;
});

alert( schedule.meetups[1].date.getDate() ); // ça fonctionne !

Résumé

  • 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 des mĂ©thodes JSON.stringify pour sĂ©rialiser en JSON et JSON.parse pour lire depuis JSON.
  • Les deux mĂ©thodes prennent en charge les fonctions du transformateur pour une lecture/Ă©criture intelligente.
  • Si un objet a toJSON, alors il est appelĂ© par JSON.stringify.

Exercices

importance: 5

Transformez l’utilisateur en JSON puis relisez-le dans une autre variable.

let user = {
  name: "John Smith",
  age: 35
};
let user = {
  name: "John Smith",
  age: 35
};

let user2 = JSON.parse(JSON.stringify(user));
importance: 5

Dans les 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 les rĂ©fĂ©rences circulaires et dans les propriĂ©tĂ©s normales. Ainsi, nous pouvons vĂ©rifier la propriĂ©tĂ© par sa valeur.

Écrivez la fonction de remplacement pour tout stringify, mais supprimez les propriĂ©tĂ©s qui font rĂ©fĂ©rence Ă  meetup:

let room = {
  number: 23
};

let meetup = {
  title: "Conference",
  occupiedBy: [{name: "John"}, {name: "Alice"}],
  place: room
};

// circular references
room.occupiedBy = meetup;
meetup.self = meetup;

alert( JSON.stringify(meetup, function replacer(key, value) {
  /* your code */
}));

/* result should be:
{
  "title":"Conference",
  "occupiedBy":[{"name":"John"},{"name":"Alice"}],
  "place":{"number":23}
}
*/
let room = {
  number: 23
};

let meetup = {
  title: "Conference",
  occupiedBy: [{name: "John"}, {name: "Alice"}],
  place: room
};

room.occupiedBy = meetup;
meetup.self = meetup;

alert( JSON.stringify(meetup, function replacer(key, value) {
  return (key != "" && value == meetup) ? undefined : value;
}));

/*
{
  "title":"Conference",
  "occupiedBy":[{"name":"John"},{"name":"Alice"}],
  "place":{"number":23}
}
*/

Ici, nous devons Ă©galement tester la key=="" pour exclure le premier appel oĂč il est normal que la valeur soit meetup.

Carte du tutoriel

Commentaires

lire ceci avant de commenter

  • Si vous avez des amĂ©liorations Ă  suggĂ©rer, merci de soumettre une issue GitHub ou une pull request au lieu de commenter.
  • Si vous ne comprenez pas quelque chose dans l'article, merci de prĂ©ciser.
  • Pour insĂ©rer quelques bouts de code, utilisez la balise <code>, pour plusieurs lignes – enveloppez-les avec la balise <pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepen
)