JSON-klassen i JavaScript

JSON-klassen i JavaScript

Denne artikel forklarer JSON-klassen i JavaScript.

Vi vil forklare JSON-klassen i JavaScript med praktiske eksempler.

YouTube Video

JSON-klassen i JavaScript

JSON-objektet har hovedsageligt to metoder. JSON.stringify() konverterer et objekt til en JSON-streng, og JSON.parse() opretter et objekt ud fra en JSON-streng. JSON er et dataudvekslingsformat, som kun kan repræsentere visse JavaScript-værdier. Funktioner, undefined, Symbol og cirkulære referencer kan ikke direkte konverteres til JSON.

JSON.stringify()

Her er først et grundlæggende eksempel på at konvertere et objekt til en JSON-streng.

1// Convert a JavaScript object to a JSON string.
2const obj = { name: "Alice", age: 30, active: true };
3const jsonString = JSON.stringify(obj);
4console.log(jsonString); // {"name":"Alice","age":30,"active":true}
  • Denne kode er det mest grundlæggende eksempel på at konvertere et almindeligt objekt til en JSON-streng. JSON.stringify returnerer strengen synkront.

Det andet argument i JSON.stringify (replacer)

Ved at angive replacer, som er det andet argument i JSON.stringify, kan du finjustere konverteringsreglerne. Her er et eksempel, hvor man bruger et array til kun at beholde bestemte egenskaber.

1// Use a replacer array to include only specific properties during stringification.
2const user = { id: 1, name: "Bob", password: "secret", role: "admin" };
3const safeJson = JSON.stringify(user, ["id", "name", "role"]);
4console.log(safeJson); // {"id":1,"name":"Bob","role":"admin"}
  • I dette eksempel udelades password for at muliggøre sikker logoutput. Dette er nyttigt, når du vil fjerne følsomme oplysninger af sikkerhedsmæssige årsager.

Brug af replacer som en funktion (til værdikonvertering og filtrering)

Hvis du ønsker mere fleksibilitet, kan du angive en funktion til at bearbejde hver nøgle og værdi. Nedenfor er et eksempel på at gemme en Date som en ISO-streng.

 1// Use a replacer function to customize serialization.
 2const data = { name: "Carol", joined: new Date("2020-01-01T12:00:00Z") };
 3const jsonCustom = JSON.stringify(data, (key, value) => {
 4  // Convert Date objects to ISO strings explicitly
 5  if (this && this[key] instanceof Date) {
 6    return this[key].toISOString();
 7  }
 8  return value;
 9});
10console.log(jsonCustom); // {"name":"Carol","joined":"2020-01-01T12:00:00.000Z"}
  • I en funktionstype replacer videregives nøgle og værdi, og den returnerede værdi bruges i den endelige JSON. this refererer til forældre-objektet, så det kan også bruges til indlejrede konverteringer.

Det grundlæggende om JSON.parse()

JSON.parse konverterer en JSON-streng tilbage til et objekt. Indpak det med try/catch, så du kan håndtere ugyldig JSON.

1// Parse a JSON string into an object and handle parsing errors.
2const jsonText = '{"title":"Example","count":42}';
3try {
4  const parsed = JSON.parse(jsonText);
5  console.log(parsed.title); // Example
6} catch (err) {
7  console.error("Invalid JSON:", err.message);
8}
  • Hvis strengen er ugyldig, vil der blive kastet en undtagelse, så husk altid at inkludere undtagelseshåndtering ved eksterne kilder.

Brugerdefineret gendannelse med reviver (eksempel på gendannelse af Date)

Ved at bruge det andet argument, reviver, i JSON.parse kan du udføre værdigengivelse. Her er et eksempel på at konvertere en gemt streng-dato tilbage til et Date-objekt.

 1// Use a reviver to turn ISO date strings back into Date objects.
 2const jsonWithDate = '{"name":"Dana","joined":"2021-06-15T09:00:00.000Z"}';
 3const obj = JSON.parse(jsonWithDate, (key, value) => {
 4  // A simple check for ISO date-like strings
 5  if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) {
 6    return new Date(value);
 7  }
 8  return value;
 9});
10console.log(obj.joined instanceof Date); // true
  • reviver bliver kaldt for hver nøgle, og den returnerede værdi bruges i det endelige objekt. Foretag venligst streng datotjek i henhold til din applikation.

Pæn formatering og argumentet space

For at udskrive med indrykning for læsbarhed skal du angive et tal eller en streng som det tredje argument til JSON.stringify.

1// Pretty-print an object with 2-space indentation for readability.
2const config = { host: "localhost", port: 3000, debug: true };
3const pretty = JSON.stringify(config, null, 2);
4console.log(pretty);
5/* {
6  "host": "localhost",
7  "port": 3000,
8  "debug": true
9} */
  • For JSON, der skal læses af mennesker, såsom logs eller uddata fra konfigurationsfiler, er det nyttigt at angive indrykning. Vær dog opmærksom på, at dette øger størrelsen.

Sådan håndteres cirkulære referencer

JSON.stringify kaster en TypeError, hvis der er en cirkulær reference. En almindelig løsning er at oprette en replacer, der bruger et seen-sæt for at undgå cirkulære referencer.

 1// Safely stringify objects that may contain circular references.
 2function safeStringify(value) {
 3  const seen = new WeakSet();
 4  return JSON.stringify(value, (key, val) => {
 5    if (val && typeof val === "object") {
 6      if (seen.has(val)) return "[Circular]";
 7      seen.add(val);
 8    }
 9    return val;
10  });
11}
12
13const a = { name: "A" };
14a.self = a;
15console.log(safeStringify(a)); // {"name":"A","self":"[Circular]"}
  • Ved at bruge en WeakSet kan du opdage cirkulære referencer uden at forårsage hukommelseslækager. I tilfælde af en cirkulær reference returneres "[Circular]". Det er også muligt at tildele et reference-ID i stedet for "[Circular]".

Brugerdefineret serialisering med toJSON-metoden

Hvis du definerer en toJSON-metode på et objekt, bruger JSON.stringify dens returværdi. Dette er nyttigt, når du vil indlejre konverteringsregler for hver type.

 1// Define toJSON on a class to customize its JSON representation.
 2class Point {
 3  constructor(x, y) {
 4    this.x = x;
 5    this.y = y;
 6  }
 7  toJSON() {
 8    // This will be used by JSON.stringify
 9    return { x: this.x, y: this.y, type: "Point" };
10  }
11}
12
13const p = new Point(10, 20);
14console.log(JSON.stringify(p)); // {"x":10,"y":20,"type":"Point"}
  • toJSON gør det muligt at definere serialiseringsregler på objektniveau, hvilket gør det mere lokalt og intuitivt end at bruge replacer.

Begrænsninger og forbehold ved JSON

Bemærkelsesværdige eksempler, der ikke kan konverteres til JSON, er undefined, funktioner, Symbol, BigInt samt cirkulære referencer. Vær også opmærksom på numerisk præcision (for eksempel store heltal og IEEE-flydende punktafrunding).

 1// Demonstrate values that can't be represented in JSON.
 2const sample = {
 3  a: undefined,
 4  b: function () {},
 5  c: Symbol("s"),
 6  d: 9007199254740993n // BigInt (note: JSON.stringify will throw on BigInt)
 7};
 8// JSON.stringify will throw for BigInt and will drop undefined, functions, symbols in objects.
 9try {
10  console.log(JSON.stringify(sample));
11} catch (err) {
12  console.error("Error during stringify:", err.message);
13}
  • Når du håndterer BigInt, skal du konvertere det til en streng eller definere dets repræsentation ved hjælp af en brugerdefineret replacer eller toJSON.

Sikkerhed (ved håndtering af utroværdig JSON)

JSON.parse i sig selv er sikker og anses for mere sikker end eval, men det er farligt at stole på det analyserede objekt og bruge det direkte til at tilgå egenskaber eller databaseforespørgsler. Valider altid, og tjek at dataene stemmer overens med det forventede skema.

1// Parse external JSON and validate expected properties before use.
2const external = '{"username":"eve","role":"user"}';
3const parsed = JSON.parse(external);
4if (typeof parsed.username === "string" && ["user","admin"].includes(parsed.role)) {
5  console.log("Safe to use parsed.username and parsed.role.");
6} else {
7  throw new Error("Invalid payload");
8}
  • For indtastningsvalidering (skemavalidering) er det robust at bruge biblioteker som ajv.

Ydelsesmæssige overvejelser

Hyppig serialisering og deserialisering af store objekter belaster CPU'en og hukommelsen. Om nødvendigt kan du overveje kun at sende forskellene, bruge binære formater (som MessagePack), eller streame (behandle data sekventielt). I browsermiljøer kan du i visse tilfælde benytte structuredClone (til kopiering) eller overførbare objekter i postMessage.

Specifik rådgivning (kort)

Du kan også overveje følgende punkter:.

  • Undgå pæn formatering i logs, og brug linje-JSON for at reducere størrelsen.
  • Objekter, der ofte serialiseres, bør gøres lette på forhånd, f.eks. ved at fjerne unødvendige egenskaber.
  • Brug replacer til at minimere gennemløb og udelukke unødvendige egenskaber.

Praktisk eksempel: Send/modtag-flow for API-anmodning

Til sidst er her en sekvens, der viser, hvordan man sikkert konverterer et objekt til JSON ved afsendelse til en server og gendanner en dato fra det modtagne svar.

 1// Prepare payload, stringify safely, send via fetch, and revive dates on response.
 2async function sendUserUpdate(url, user) {
 3  // Remove sensitive info before sending
 4  const payload = JSON.stringify(user, (k, v) => (k === "password" ? undefined : v));
 5  const res = await fetch(url, {
 6    method: "POST",
 7    headers: { "Content-Type": "application/json" },
 8    body: payload
 9  });
10
11  const text = await res.text();
12  // Reviver: convert ISO date strings back to Date
13  const data = JSON.parse(text, (key, value) => {
14    if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) {
15      return new Date(value);
16    }
17    return value;
18  });
19  return data;
20}
  • I dette eksempel udelades password før afsendelse, og dato bliver gendannet af reviver ved modtagelse. I virkelig drift skal du tilføje fejlhåndtering og timeout-behandling.

Sammendrag

Ved hjælp af JSON.stringify() og JSON.parse() kan du konvertere mellem objekter og strenge. Du kan tilpasse konverteringsprocessen ved hjælp af replacer og reviver, og hvis du implementerer toJSON i en klasse, kan du også styre hvert objekt individuelt. Cirkulære referencer, BigInt, funktioner osv. kan ikke håndteres som de er, så du skal behandle dem på forhånd.

Valider altid ekstern input, og sørg for, at følsomme oplysninger ikke medtages i logs eller kommunikation. Hvis datamængden er stor, er det effektivt at undgå pæn formatering, overveje differentiel transmission eller bruge binære formater.

Du kan følge med i ovenstående artikel ved hjælp af Visual Studio Code på vores YouTube-kanal. Husk også at tjekke YouTube-kanalen.

YouTube Video