Klassen `JSON` i JavaScript
Den här artikeln förklarar klassen JSON i JavaScript.
Vi kommer att förklara klassen JSON i JavaScript med praktiska exempel.
YouTube Video
Klassen JSON i JavaScript
JSON-objektet har framför allt två metoder. JSON.stringify() omvandlar ett objekt till en JSON-sträng och JSON.parse() skapar ett objekt från en JSON-sträng. JSON är ett datautbytesformat som endast kan uttrycka vissa JavaScript-värden. Funktioner, undefined, Symbol och cirkulära referenser kan inte direkt konverteras till JSON.
JSON.stringify()
Först, här är ett grundläggande exempel på att konvertera ett objekt till en JSON-sträng.
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}
- Den här koden är det mest grundläggande exemplet på att konvertera ett vanligt objekt till en JSON-sträng.
JSON.stringifyreturnerar strängen synkront.
Det andra argumentet till JSON.stringify (replacer)
Genom att ange replacer som det andra argumentet till JSON.stringify kan du noggrant styra konverteringsreglerna. Här är ett exempel där en array används för att endast behålla specifika egenskaper.
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 det här exemplet exkluderas
passwordså att säker loggning är möjlig. Detta är användbart när du vill ta bort känslig information av säkerhetsskäl.
Att använda replacer som en funktion (för värdeomvandling eller filtrering)
Om du vill ha mer flexibilitet kan du ange en funktion för att bearbeta varje nyckel och värde. Nedan är ett exempel på att behålla ett Date-objekt som en ISO-sträng.
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
replacer-funktion skickas nyckel och värde in, och returvärdet används i den slutliga JSON-strängen.thisrefererar till det överordnade objektet och kan därför användas för nästlade konverteringar.
Grunderna i JSON.parse()
JSON.parse konverterar en JSON-sträng tillbaka till ett objekt. Använd try/catch för att hantera ogiltig 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}- Om strängen är ogiltig kommer ett undantag att kastas, så inkludera alltid undantagshantering när du arbetar med externa källor.
Anpassad återställning med hjälp av reviver (exempel på att återskapa Date)
Genom att använda det andra argumentet reviver till JSON.parse kan du återställa värden. Här är ett exempel på att konvertera ett sparat datum i strängformat tillbaka till ett 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
reviveranropas för varje nyckel, och returvärdet används i det slutliga objektet. Utför noggrann datumformatskontroll enligt din applikations krav.
Snygg utskrift och argumentet space
För att få indrag vid utskrift, ange ett tal eller en sträng som tredje argument till 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} */- För JSON som ska läsas av människor, till exempel loggar eller konfigurationsfiler, är det bra att specificera indrag. Var dock medveten om att detta ökar filstorleken.
Hur man hanterar cirkulära referenser
JSON.stringify kastar ett TypeError-undantag om det finns en cirkulär referens. En vanlig lösning är att skapa en replacer som använder en seen-uppsättning för att undvika cirkulära referenser.
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]"}
- Genom att använda en
WeakSetkan du upptäcka cirkulära referenser utan att orsaka minnesläckor. I fall av en cirkulär referens returneras"[Circular]". Det går också att tilldela ett referens-ID istället för"[Circular]".
Anpassad serialisering med metoden toJSON
Om du definierar en toJSON-metod på ett objekt används dess returvärde av JSON.stringify. Detta är användbart när du vill ange konverteringsregler för varje typ.
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"}
toJSONlåter dig definiera serialiseringsregler på objektnivå, vilket gör det mer lokalt och intuitivt än att användareplacer.
Begränsningar och varningar för JSON
Anmärkningsvärda exempel som inte kan konverteras till JSON är undefined, funktioner, Symbol, BigInt och cirkulära referenser. Var även uppmärksam på numerisk precision (till exempel stora heltal och IEEE-flyttalsavrundning).
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 hanterar
BigInt, konvertera det till en sträng eller definiera dess representation med en egenreplacerellertoJSON.
Säkerhet (vid hantering av opålitlig JSON)
JSON.parse i sig är säker och anses säkrare än eval, men det är farligt att direkt lita på och använda det avkodade objektet för egenskapsåtkomst eller databasfrågor. Validera alltid och kontrollera att datan överensstämmer med det förväntade schemat.
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}- För indata- och schemavalidering är det robust att använda bibliotek som
ajv.
Prestandahänsyn
Att ofta serialisera och deserialisera stora objekt belastar CPU och minne. Om det behövs kan du överväga att endast skicka skillnaderna, använda binära format (som MessagePack), eller använda strömning (sekventiell databehandling). I webbläsarmiljöer kan du ibland använda structuredClone (för kopiering) eller överförbara objekt i postMessage.
Specifika råd (kortfattat)
Du kan också tänka på följande punkter:.
- För loggar, undvik snygg utskrift och använd enradig JSON för att minska storleken.
- Objekt som serialiseras ofta bör göras lättviktiga i förväg, till exempel genom att ta bort onödiga egenskaper.
- Använd
replacerför att minimera genomgång och utesluta onödiga egenskaper.
Praktiskt exempel: Flöde vid sändning och mottagning av API-förfrågan
Avslutningsvis, här är en sekvens som visar hur du säkert konverterar ett objekt till JSON för att skicka till en server och återskapar ett datum från det mottagna svaret.
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 det här exemplet exkluderas
passwordinnan sändning, och datumet återskapas avrevivervid mottagning. I faktisk drift behöver du lägga till felhantering och timeout-behandling.
Sammanfattning
Med hjälp av JSON.stringify() och JSON.parse() kan du konvertera mellan objekt och strängar. Du kan anpassa konverteringsprocessen med replacer och reviver, och om du implementerar toJSON i en klass kan du även styra varje objekt individuellt. Cirkulära referenser, BigInt, funktioner m.m. kan inte hanteras direkt, så du behöver behandla dem i förväg.
Validera alltid extern indata och säkerställ att känslig information inte ingår i loggar eller kommunikation. Om datamängden är stor är det effektivt att undvika snygg utskrift, överväga differentialsändning eller använda binära format.
Du kan följa med i artikeln ovan med hjälp av Visual Studio Code på vår YouTube-kanal. Vänligen kolla även in YouTube-kanalen.