Nehmen wir an, wir haben ein komplexes Objekt und möchten es in einen String konvertieren, über ein Netzwerk senden oder einfach zu Protokollierungszwecken ausgeben.
Selbstverständlich sollte ein solcher String alle wichtigen Eigenschaften enthalten.
Wir könnten die Konvertierung so umsetzen:
let user = { Name: „John“, Alter: 30, toString() { return `{name: "${this.name}", age: ${this.age}}`; } }; Warnung(Benutzer); // {Name: „John“, Alter: 30}
…Aber im Laufe der Entwicklung kommen neue Eigenschaften hinzu, alte Eigenschaften werden umbenannt und entfernt. Solche toString
jedes Mal zu aktualisieren, kann mühsam sein. Wir könnten versuchen, die darin enthaltenen Eigenschaften in einer Schleife zu durchlaufen, aber was ist, wenn das Objekt komplex ist und verschachtelte Objekte in den Eigenschaften enthält? Wir müssten auch ihre Konvertierung implementieren.
Glücklicherweise ist es nicht nötig, den Code zu schreiben, um all dies zu bewältigen. Die Aufgabe wurde bereits gelöst.
Die JSON (JavaScript Object Notation) ist ein allgemeines Format zur Darstellung von Werten und Objekten. Es wird wie im RFC 4627-Standard beschrieben. Ursprünglich wurde es für JavaScript entwickelt, aber auch viele andere Sprachen verfügen über Bibliotheken, die es verarbeiten können. Daher ist es einfach, JSON für den Datenaustausch zu verwenden, wenn der Client JavaScript verwendet und der Server auf Ruby/PHP/Java/Was auch immer geschrieben ist.
JavaScript bietet Methoden:
JSON.stringify
zum Konvertieren von Objekten in JSON.
JSON.parse
um JSON wieder in ein Objekt umzuwandeln.
Hier zum Beispiel JSON.stringify
wir einen Schüler:
lass student = { Name: 'John', Alter: 30, isAdmin: false, Kurse: ['html', 'css', 'js'], Ehepartner: null }; let json = JSON.stringify(student); Alert(typeof json); // wir haben eine Zeichenfolge! alarm(json); /* JSON-codiertes Objekt: { „Name“: „John“, „Alter“: 30, „isAdmin“: false, „Kurse“: [„html“, „css“, „js“], „Ehepartner“: null } */
Die Methode JSON.stringify(student)
nimmt das Objekt und wandelt es in einen String um.
Der resultierende json
String wird als JSON-codiertes oder serialisiertes oder stringifiziertes oder gemarshalltes Objekt bezeichnet. Wir sind bereit, es über das Kabel zu senden oder in einem einfachen Datenspeicher abzulegen.
Bitte beachten Sie, dass ein JSON-codiertes Objekt mehrere wichtige Unterschiede zum Objektliteral aufweist:
Zeichenfolgen verwenden doppelte Anführungszeichen. Keine einfachen Anführungszeichen oder Backticks in JSON. Aus 'John'
wird also "John"
.
Objekteigenschaftennamen werden ebenfalls in doppelte Anführungszeichen gesetzt. Das ist obligatorisch. Also wird age:30
zu "age":30
.
JSON.stringify
kann auch auf Grundelemente angewendet werden.
JSON unterstützt folgende Datentypen:
Objekte { ... }
Arrays [ ... ]
Primitive:
Saiten,
Zahlen,
boolesche Werte true/false
,
null
.
Zum Beispiel:
// Eine Zahl in JSON ist nur eine Zahl alarm( JSON.stringify(1) ) // 1 // Ein String in JSON ist immer noch ein String, aber in doppelte Anführungszeichen gesetzt alarm( JSON.stringify('test') ) // "test" alarm( JSON.stringify(true) ); // WAHR alarm( JSON.stringify([1, 2, 3]) ); // [1,2,3]
JSON ist eine sprachunabhängige Nur-Daten-Spezifikation, daher werden einige JavaScript-spezifische Objekteigenschaften von JSON.stringify
übersprungen.
Nämlich:
Funktionseigenschaften (Methoden).
Symbolische Schlüssel und Werte.
Eigenschaften, die undefined
speichern.
let user = { sayHi() { // ignoriert alarm("Hallo"); }, [Symbol("id")]: 123, // ignoriert etwas: undefiniert // ignoriert }; alarm( JSON.stringify(user) ); // {} (leeres Objekt)
Normalerweise ist das in Ordnung. Wenn das nicht das ist, was wir wollen, werden wir bald sehen, wie wir den Prozess anpassen können.
Das Tolle ist, dass verschachtelte Objekte automatisch unterstützt und konvertiert werden.
Zum Beispiel:
let meetup = { Titel: „Konferenz“, Zimmer: { Anzahl: 23, Teilnehmer: ["john", "ann"] } }; alarm( JSON.stringify(meetup) ); /* Die gesamte Struktur ist stringifiziert: { „title“: „Konferenz“, "room":{"number":23,"participants":["john",ann"]}, } */
Die wichtige Einschränkung: Es dürfen keine Zirkelbezüge vorhanden sein.
Zum Beispiel:
let room = { Nummer: 23 }; let meetup = { Titel: „Konferenz“, Teilnehmer: ["john", "ann"] }; meetup.place = Raum; // Meetup-Referenzraum room.occupiedBy = meetup; // Raumreferenzen treffen JSON.stringify(meetup); // Fehler: Zirkuläre Struktur wird in JSON konvertiert
Hier schlägt die Konvertierung aufgrund des Zirkelverweises fehl: room.occupiedBy
verweist auf meetup
und meetup.place
verweist auf room
:
Die vollständige Syntax von JSON.stringify
lautet:
let json = JSON.stringify(value[, replacementer, space])
Wert
Ein zu kodierender Wert.
Ersatz
Array von zu kodierenden Eigenschaften oder eine Zuordnungsfunktion function(key, value)
.
Raum
Für die Formatierung zu verwendender Speicherplatz
Meistens wird JSON.stringify
nur mit dem ersten Argument verwendet. Wenn wir jedoch den Ersetzungsprozess verfeinern müssen, beispielsweise um Zirkelverweise herauszufiltern, können wir das zweite Argument von JSON.stringify
verwenden.
Wenn wir ihm ein Array von Eigenschaften übergeben, werden nur diese Eigenschaften codiert.
Zum Beispiel:
let room = { Nummer: 23 }; let meetup = { Titel: „Konferenz“, Teilnehmer: [{Name: „John“}, {Name: „Alice“}], Ort: Raum // Meetup-Referenzraum }; room.occupiedBy = meetup; // Raumreferenzen treffen alarm( JSON.stringify(meetup, ['title', 'participants']) ); // {"title": "Konferenz", "Teilnehmer": [{}, {}]}
Hier sind wir wahrscheinlich zu streng. Die Eigenschaftsliste wird auf die gesamte Objektstruktur angewendet. Die Objekte in participants
sind also leer, da name
nicht in der Liste enthalten ist.
Nehmen wir alle Eigenschaften außer room.occupiedBy
in die Liste auf, die den Zirkelverweis verursachen würden:
let room = { Nummer: 23 }; let meetup = { Titel: „Konferenz“, Teilnehmer: [{Name: „John“}, {Name: „Alice“}], Ort: Raum // Meetup-Referenzraum }; room.occupiedBy = meetup; // Raumreferenzen treffen alarm( JSON.stringify(meetup, ['title', 'participants', 'place', 'name', 'number']) ); /* { „title“: „Konferenz“, „Teilnehmer“:[{“name“:“John“},{“name“:“Alice“}], "Ort":{"Nummer":23} } */
Jetzt wird alles außer occupiedBy
serialisiert. Aber die Liste der Eigenschaften ist ziemlich lang.
Glücklicherweise können wir als replacer
eine Funktion anstelle eines Arrays verwenden.
Die Funktion wird für jedes (key, value)
Paar aufgerufen und sollte den „ersetzten“ Wert zurückgeben, der anstelle des ursprünglichen verwendet wird. Oder undefined
, wenn der Wert übersprungen werden soll.
In unserem Fall können wir value
„wie er ist“ für alles mit Ausnahme von occupiedBy
“ zurückgeben. Um occupiedBy
zu ignorieren, gibt der folgende Code undefined
zurück:
let room = { Nummer: 23 }; let meetup = { Titel: „Konferenz“, Teilnehmer: [{Name: „John“}, {Name: „Alice“}], Ort: Raum // Meetup-Referenzraum }; room.occupiedBy = meetup; // Raumreferenzen treffen alarm( JSON.stringify(meetup, function replacementer(key, value) { alarm(`${key}: ${value}`); return (key == 'occupiedBy') ? undefiniert: Wert; })); /* Schlüssel:Wert-Paare, die zum Ersetzen kommen: : [Objekt Objekt] Titel: Konferenz Teilnehmer: [Objekt Objekt],[Objekt Objekt] 0: [Objekt Objekt] Name: John 1: [Objekt Objekt] Name: Alice Ort: [Objekt Objekt] Nummer: 23 besetztBy: [Objekt Objekt] */
Bitte beachten Sie, dass die replacer
jedes Schlüssel/Wert-Paar abruft, einschließlich verschachtelter Objekte und Array-Elemente. Es wird rekursiv angewendet. Der Wert this
Inside replacer
ist das Objekt, das die aktuelle Eigenschaft enthält.
Der erste Anruf ist etwas Besonderes. Es wird mit einem speziellen „Wrapper-Objekt“ erstellt: {"": meetup}
. Mit anderen Worten: Das erste Paar (key, value)
hat einen leeren Schlüssel und der Wert ist das Zielobjekt als Ganzes. Deshalb lautet die erste Zeile im obigen Beispiel ":[object Object]"
.
Die Idee besteht darin, so viel Leistung wie möglich für replacer
bereitzustellen: Er hat die Möglichkeit, bei Bedarf sogar das gesamte Objekt zu analysieren und zu ersetzen/überspringen.
Das dritte Argument von JSON.stringify(value, replacer, space)
ist die Anzahl der Leerzeichen, die für eine hübsche Formatierung verwendet werden sollen.
Bisher hatten alle stringifizierten Objekte keine Einrückungen und zusätzliche Leerzeichen. Das ist in Ordnung, wenn wir ein Objekt über ein Netzwerk senden möchten. Das space
wird ausschließlich für eine schöne Ausgabe verwendet.
Hier weist space = 2
JavaScript an, verschachtelte Objekte in mehreren Zeilen anzuzeigen, wobei zwei Leerzeichen innerhalb eines Objekts eingerückt werden:
let user = { Name: „John“, Alter: 25, Rollen: { isAdmin: false, isEditor: wahr } }; alarm(JSON.stringify(user, null, 2)); /* Einrückungen mit zwei Leerzeichen: { „Name“: „John“, „Alter“: 25, "Rollen": { „isAdmin“: false, „isEditor“: wahr } } */ /* für JSON.stringify(user, null, 4) wäre das Ergebnis stärker eingerückt: { „Name“: „John“, „Alter“: 25, "Rollen": { „isAdmin“: false, „isEditor“: wahr } } */
Das dritte Argument kann auch ein String sein. In diesem Fall wird die Zeichenfolge anstelle einer Anzahl von Leerzeichen zum Einrücken verwendet.
Der space
Parameter wird ausschließlich für Protokollierungs- und Nice-Output-Zwecke verwendet.
Wie toString
für die String-Konvertierung kann ein Objekt die Methode toJSON
für die JSON-Konvertierung bereitstellen. JSON.stringify
ruft es automatisch auf, sofern verfügbar.
Zum Beispiel:
let room = { Nummer: 23 }; let meetup = { Titel: „Konferenz“, Datum: neues Datum(Date.UTC(2017, 0, 1)), Zimmer }; alarm( JSON.stringify(meetup) ); /* { „title“: „Konferenz“, „Datum“: „2017-01-01T00:00:00.000Z“, // (1) "room": {"number":23} // (2) } */
Hier können wir sehen, dass date
(1)
zu einer Zeichenfolge wurde. Das liegt daran, dass alle Datumsangaben über eine integrierte toJSON
-Methode verfügen, die eine solche Zeichenfolge zurückgibt.
Fügen wir nun ein benutzerdefiniertes toJSON
für unseren room
(2)
hinzu:
let room = { Anzahl: 23, toJSON() { gib diese Nummer zurück; } }; let meetup = { Titel: „Konferenz“, Zimmer }; alarm( JSON.stringify(room) ); // 23 alarm( JSON.stringify(meetup) ); /* { „title“: „Konferenz“, „Raum“: 23 } */
Wie wir sehen können, wird toJSON
sowohl für den direkten Aufruf von JSON.stringify(room)
als auch wenn room
in einem anderen codierten Objekt verschachtelt ist, verwendet.
Um einen JSON-String zu dekodieren, benötigen wir eine weitere Methode namens JSON.parse.
Die Syntax:
let value = JSON.parse(str[, reviver]);
str
JSON-String zum Parsen.
Erwecker
Optionale Funktion (Schlüssel, Wert), die für jedes Paar (key, value)
aufgerufen wird und den Wert transformieren kann.
Zum Beispiel:
// stringifiziertes Array let zahlen = "[0, 1, 2, 3]"; zahlen = JSON.parse(zahlen); alarm( zahlen[1] ); // 1
Oder für verschachtelte Objekte:
let userData = '{ "name": "John", "age": 35, "isAdmin": false, "friends": [0,1,2,3] }'; let user = JSON.parse(userData); alarm( user.friends[1] ); // 1
Der JSON kann so komplex wie nötig sein, Objekte und Arrays können andere Objekte und Arrays enthalten. Sie müssen jedoch demselben JSON-Format entsprechen.
Hier sind typische Fehler in handgeschriebenem JSON (manchmal müssen wir es zu Debugging-Zwecken schreiben):
let json = `{ Name: „John“, // Fehler: Eigenschaftsname ohne Anführungszeichen „Nachname“: „Smith“, // Fehler: einfache Anführungszeichen im Wert (muss doppelt sein) 'isAdmin': false // Fehler: einfache Anführungszeichen im Schlüssel (muss doppelt sein) „Geburtstag“: neues Datum(2000, 2, 3), // Fehler: „neu“ ist nicht erlaubt, nur nackte Werte „friends“: [0,1,2,3] // hier ist alles in Ordnung }`;
Außerdem unterstützt JSON keine Kommentare. Durch das Hinzufügen eines Kommentars zu JSON wird dieser ungültig.
Es gibt ein anderes Format namens JSON5, das Schlüssel, Kommentare usw. ohne Anführungszeichen zulässt. Dies ist jedoch eine eigenständige Bibliothek, die nicht in der Spezifikation der Sprache enthalten ist.
Das reguläre JSON ist nicht deshalb so streng, weil seine Entwickler faul sind, sondern um einfache, zuverlässige und sehr schnelle Implementierungen des Parsing-Algorithmus zu ermöglichen.
Stellen Sie sich vor, wir haben ein stringifiziertes meetup
Objekt vom Server erhalten.
Es sieht so aus:
// Titel: (Titel des Treffens), Datum: (Datum des Treffens) let str = '{"title": "Konferenz", "Datum": "2017-11-30T12:00:00.000Z"}';
… Und jetzt müssen wir es deserialisieren , um es wieder in ein JavaScript-Objekt umzuwandeln.
Machen wir es, indem wir JSON.parse
aufrufen:
let str = '{"title": "Konferenz", "Datum": "2017-11-30T12:00:00.000Z"}'; let meetup = JSON.parse(str); alarm( meetup.date.getDate() ); // Fehler!
Hoppla! Ein Fehler!
Der Wert von meetup.date
ist eine Zeichenfolge, kein Date
Objekt. Wie könnte JSON.parse
wissen, dass es diese Zeichenfolge in ein Date
umwandeln soll?
Übergeben wir JSON.parse
die Wiederbelebungsfunktion als zweites Argument, die alle Werte „wie sie sind“ zurückgibt, aber date
wird zu einem Date
:
let str = '{"title": "Konferenz", "Datum": "2017-11-30T12:00:00.000Z"}'; let meetup = JSON.parse(str, function(key, value) { if (key == 'date') return new Date(value); Rückgabewert; }); alarm( meetup.date.getDate() ); // funktioniert jetzt!
Das funktioniert übrigens auch für verschachtelte Objekte:
let scheme = `{ „Meetups“: [ {"title": "Konferenz", "Datum": "2017-11-30T12:00:00.000Z"}, {"title": "Geburtstag", "date": "2017-04-18T12:00:00.000Z"} ] }`; Schedule = JSON.parse(schedule, function(key, value) { if (key == 'date') return new Date(value); Rückgabewert; }); alarm( Schedule.meetups[1].date.getDate() ); // funktioniert!
JSON ist ein Datenformat, das für die meisten Programmiersprachen über einen eigenen unabhängigen Standard und Bibliotheken verfügt.
JSON unterstützt einfache Objekte, Arrays, Zeichenfolgen, Zahlen, boolesche Werte und null
.
JavaScript bietet die Methoden JSON.stringify zum Serialisieren in JSON und JSON.parse zum Lesen aus JSON.
Beide Methoden unterstützen Transformatorfunktionen für intelligentes Lesen/Schreiben.
Wenn ein Objekt toJSON
hat, wird es von JSON.stringify
aufgerufen.
Wichtigkeit: 5
Wandeln Sie den user
in JSON um und lesen Sie ihn dann wieder in eine andere Variable ein.
let user = { Name: „John Smith“, Alter: 35 };
let user = { Name: „John Smith“, Alter: 35 }; let user2 = JSON.parse(JSON.stringify(user));
Wichtigkeit: 5
In einfachen Fällen von Zirkelverweisen können wir eine problematische Eigenschaft anhand ihres Namens von der Serialisierung ausschließen.
Aber manchmal können wir nicht einfach den Namen verwenden, da er sowohl in Zirkelverweisen als auch in normalen Eigenschaften verwendet werden kann. So können wir die Immobilie anhand ihres Werts überprüfen.
Schreiben Sie eine replacer
, um alles in Strings umzuwandeln, aber entfernen Sie Eigenschaften, die auf meetup
verweisen:
let room = { Nummer: 23 }; let meetup = { Titel: „Konferenz“, besetztBy: [{Name: „John“}, {Name: „Alice“}], Ort: Raum }; // Zirkelverweise room.occupiedBy = meetup; meetup.self = meetup; alarm( JSON.stringify(meetup, function replacementer(key, value) { /* Ihr Code */ })); /* Ergebnis sollte sein: { „title“: „Konferenz“, „occupiedBy“:[{“name“:“John“},{“name“:“Alice“}], "Ort":{"Nummer":23} } */
let room = { Nummer: 23 }; let meetup = { Titel: „Konferenz“, besetztBy: [{Name: „John“}, {Name: „Alice“}], Ort: Raum }; room.occupiedBy = meetup; meetup.self = meetup; alarm( JSON.stringify(meetup, function replacementer(key, value) { return (key != "" && value == meetup) ? undefiniert: Wert; })); /* { „title“: „Konferenz“, „occupiedBy“:[{“name“:“John“},{“name“:“Alice“}], "Ort":{"Nummer":23} } */
Hier müssen wir auch key==""
testen, um den ersten Aufruf auszuschließen, bei dem der value
normalerweise meetup
ist.