JSON (JavaScript Object Notation) ist ein Nur-Text-Format zur Datenspeicherung. Es ist als Datenaustauschformat für Webservices, Konfigurationsdateien und vieles mehr sehr beliebt geworden. ECMAScript 5 verfügt über eine API zur Konvertierung von einem String im JSON-Format in einen JavaScript-Wert (Parsen) und umgekehrt (Stringifizieren).
Dieser Abschnitt erklärt, was JSON ist und wie es entstanden ist.
JSON speichert Daten als Nur-Text. Seine Grammatik ist eine Teilmenge der Grammatik von JavaScript-Ausdrücken. Zum Beispiel:
{"first":"Jane","last":"Porter","married":true,"born":1890,"friends":["Tarzan","Cheeta"]}
JSON verwendet die folgenden Konstrukte aus JavaScript-Ausdrücken
nullEs hält sich an diese Regeln
'mystr' sind illegal. Douglas Crockford entdeckte JSON im Jahr 2001. Er gab ihm einen Namen und erstellte eine Spezifikation unter http://json.org
Ich habe JSON entdeckt. Ich behaupte nicht, JSON erfunden zu haben, da es bereits in der Natur existierte. Was ich getan habe, war, es zu finden, ihm einen Namen zu geben und zu beschreiben, wie es nützlich ist. Ich behaupte nicht, die erste Person zu sein, die es entdeckt hat; ich weiß, dass es andere Leute gab, die es mindestens ein Jahr vor mir entdeckt haben. Das früheste Vorkommen, das ich gefunden habe, war, dass jemand bei Netscape JavaScript-Array-Literale für die Datenkommunikation bereits 1996 verwendete, was mindestens fünf Jahre war, bevor ich auf die Idee stieß.
Anfangs wollte Crockford, dass JSON den Namen JavaScript Markup Language hat, aber das Akronym JSML war bereits von der JSpeech Markup Language belegt.
Die JSON-Spezifikation wurde in viele menschliche Sprachen übersetzt, und es gibt jetzt Bibliotheken für viele Programmiersprachen, die das Parsen und Generieren von JSON unterstützen.
Douglas Crockford erstellte eine JSON-Visitenkarte mit einem Logo auf der Vorderseite (siehe Abbildung 22-1) und der vollständigen Grammatik auf der Rückseite (siehe Abbildung 22-2). Das macht visuell deutlich, wie positiv einfach JSON ist.
Die Grammatik kann wie folgt transkribiert werden
{ }
{ Mitglieder }
Paar
Paar , Mitglieder
: Wert
[ ]
[ Elemente ]
Wert
Wert , Elemente
string
number
object
Array
true
false
null
""
" Zeichen "
Zeichen
Zeichen Zeichen
beliebiger-Unicode-Zeichen-außer-"-oder-\-oder-Steuerzeichen
\" \\ \/ \b \f \n \r \t
\u vier-Hex-Ziffern
Ganzzahl
Ganzzahl Bruch
Ganzzahl Exponent
Ganzzahl Bruch Exponent
Ziffer
Ziffer1-9 Ziffern
- Ziffer
- Ziffer1-9 Ziffern
. ZiffernZiffer
Ziffer Ziffern
e e+ e-
E E+ E-
Die globale Variable JSON dient als Namespace für Funktionen, die Strings mit JSON-Daten erzeugen und parsen.
JSON.stringify(value, replacer?, space?) übersetzt den JavaScript-Wert value in einen String im JSON-Format. Es hat zwei optionale Argumente.
Der optionale Parameter replacer wird verwendet, um value vor dem Stringifizieren zu ändern. Er kann sein
Ein Knotenbesucher (siehe Daten über Knotenbesucher transformieren), der den Baum von Werten transformiert, bevor er stringifiziert wird. Zum Beispiel
functionreplacer(key,value){if(typeofvalue==='number'){value=2*value;}returnvalue;}
Verwendung des Replacer
> JSON.stringify({ a: 5, b: [ 2, 8 ] }, replacer)
'{"a":10,"b":[4,16]}'Eine Whitelist von Eigenschaftsschlüsseln, die alle Eigenschaften (von Nicht-Array-Objekten) verbirgt, deren Schlüssel nicht in der Liste enthalten sind. Zum Beispiel
> JSON.stringify({foo: 1, bar: {foo: 1, bar: 1}}, ['bar'])
'{"bar":{"bar":1}}'Die Whitelist hat keine Auswirkungen auf Arrays
> JSON.stringify(['a', 'b'], ['0']) '["a","b"]'
Der optionale Parameter space beeinflusst die Formatierung der Ausgabe. Ohne diesen Parameter ist das Ergebnis von stringify eine einzelne Textzeile
> console.log(JSON.stringify({a: 0, b: ['\n']}))
{"a":0,"b":["\n"]}Mit ihm werden Zeilenumbrüche eingefügt und jede Verschachtelungsebene über Arrays und Objekte erhöht die Einrückung. Es gibt zwei Möglichkeiten, anzugeben, wie eingerückt werden soll
Multipliziere die Zahl mit der Einrückungsebene und rücke die Zeile um so viele Leerzeichen ein. Zahlen kleiner als 0 werden als 0 interpretiert; Zahlen größer als 10 werden als 10 interpretiert
> console.log(JSON.stringify({a: 0, b: ['\n']}, null, 2))
{
"a": 0,
"b": [
"\n"
]
}Um einzurücken, wiederhole den gegebenen String einmal für jede Einrückungsebene. Nur die ersten 10 Zeichen des Strings werden verwendet
> console.log(JSON.stringify({a: 0, b: ['\n']}, null, '|--'))
{
|--"a": 0,
|--"b": [
|--|--"\n"
|--]
}Daher gibt die folgende Invokation von JSON.stringify() ein Objekt als schön formatierten Baum aus
JSON.stringify(data,null,4)
In Objekten berücksichtigt JSON.stringify() nur aufzählbare eigene Eigenschaften (siehe Eigenschaftenattribute und Eigenschaftsdeskriptoren). Das folgende Beispiel zeigt, dass die nicht aufzählbare eigene Eigenschaft obj.foo ignoriert wird:
> var obj = Object.defineProperty({}, 'foo', { enumerable: false, value: 7 });
> Object.getOwnPropertyNames(obj)
[ 'foo' ]
> obj.foo
7
> JSON.stringify(obj)
'{}'Wie JSON.stringify() Werte behandelt, die von JSON nicht unterstützt werden (wie Funktionen und undefined), hängt davon ab, wo es sie findet. Ein nicht unterstützter Wert selbst führt dazu, dass stringify() undefined anstelle eines Strings zurückgibt
> JSON.stringify(function () {})
undefinedEigenschaften, deren Werte nicht unterstützt werden, werden einfach ignoriert
> JSON.stringify({ foo: function () {} })
'{}'Nicht unterstützte Werte in Arrays werden als nulls stringifiziert
> JSON.stringify([ function () {} ])
'[null]'Wenn JSON.stringify() auf ein Objekt trifft, das eine toJSON-Methode hat, verwendet es diese Methode, um einen zu stringifizierenden Wert zu erhalten. Zum Beispiel:
> JSON.stringify({ toJSON: function () { return 'Cool' } })
'"Cool"'Daten haben bereits eine toJSON-Methode , die einen ISO 8601-Datumsstring erzeugt:
> JSON.stringify(new Date('2011-07-29'))
'"2011-07-28T22:00:00.000Z"'Die vollständige Signatur einer toJSON-Methode lautet wie folgt
function(key)
Der key-Parameter ermöglicht es Ihnen, je nach Kontext unterschiedlich zu stringifizieren. Es ist immer ein String und gibt an, wo Ihr Objekt im Elternobjekt gefunden wurde
Ich werde toJSON() anhand des folgenden Objekts demonstrieren
varobj={toJSON:function(key){// Use JSON.stringify for nicer-looking outputconsole.log(JSON.stringify(key));return0;}};
Wenn Sie JSON.stringify() verwenden, wird jedes Vorkommen von obj durch 0 ersetzt. Die toJSON()-Methode wird darüber informiert, dass obj am Eigenschaftsschlüssel 'foo' und am Array-Index 0 angetroffen wurde
> JSON.stringify({ foo: obj, bar: [ obj ]})
"foo"
"0"
'{"foo":0,"bar":[0]}'Die integrierten toJSON()-Methoden sind wie folgt:
Boolean.prototype.toJSON()
Number.prototype.toJSON()
String.prototype.toJSON()
Date.prototype.toJSON()
JSON.parse(text, reviver?) parst die JSON-Daten in text und gibt einen JavaScript-Wert zurück. Hier sind einige Beispiele:
> JSON.parse("'String'") // illegal quotes
SyntaxError: Unexpected token ILLEGAL
> JSON.parse('"String"')
'String'
> JSON.parse('123')
123
> JSON.parse('[1, 2, 3]')
[ 1, 2, 3 ]
> JSON.parse('{ "hello": 123, "world": 456 }')
{ hello: 123, world: 456 }Der optionale Parameter reviver ist ein Knotenbesucher (siehe Daten über Knotenbesucher transformieren) und kann verwendet werden, um die geparsten Daten zu transformieren. In diesem Beispiel übersetzen wir Datums-Strings in Datums-Objekte:
functiondateReviver(key,value){if(typeofvalue==='string'){varx=Date.parse(value);if(!isNaN(x)){// valid date string?returnnewDate(x);}}returnvalue;}
Und hier ist die Interaktion
> var str = '{ "name": "John", "birth": "2011-07-28T22:00:00.000Z" }';
> JSON.parse(str, dateReviver)
{ name: 'John', birth: Thu, 28 Jul 2011 22:00:00 GMT }Sowohl JSON.stringify() als auch JSON.parse() ermöglichen es Ihnen, JavaScript-Daten zu transformieren, indem Sie eine Funktion übergeben:
JSON.stringify() ermöglicht es Ihnen, die JavaScript-Daten zu ändern, bevor sie in JSON umgewandelt werden.JSON.parse() parst JSON und ermöglicht es Ihnen dann, die resultierenden JavaScript-Daten nachzubearbeiten.Die JavaScript-Daten sind ein Baum, dessen Verbundknoten Arrays und Objekte sind und dessen Blätter primitive Werte (Booleans, Zahlen, Strings, null) sind. Nennen wir die Transformationsfunktion, die Sie übergeben, Knotenbesucher. Die Methoden iterieren über den Baum und rufen den Besucher für jeden Knoten auf. Sie hat dann die Möglichkeit, den Knoten zu ersetzen oder zu löschen. Der Knotenbesucher hat die Signatur
functionnodeVisitor(key,value)
Die Parameter sind:
this
Schlüssel
key ist immer ein String.Wert
Der Wurzelknoten root hat kein Elternteil. Wenn root besucht wird, wird ein Pseudoparent für ihn erstellt und die Parameter haben die folgenden Werte
this ist { '': root }.key ist ''.value ist root.Der Knotenbesucher hat drei Optionen für die Rückgabe eines Wertes
value unverändert zurück. Dann wird keine Änderung vorgenommen.undefined zurück. Dann wird der Knoten entfernt.Das Folgende ist ein Beispiel für einen Knotenbesucher. Es protokolliert, welche Werte ihm übergeben wurden.
functionnodeVisitor(key,value){console.log([// Use JSON.stringify for nicer-looking outputJSON.stringify(this),// parentJSON.stringify(key),JSON.stringify(value)].join(' # '));returnvalue;// don't change node}
Verwenden wir diese Funktion, um zu untersuchen, wie die JSON-Methoden über JavaScript-Daten iterieren.
> JSON.stringify(['a','b'], nodeVisitor)
{"":["a","b"]} # "" # ["a","b"]
["a","b"] # "0" # "a"
["a","b"] # "1" # "b"
'["a","b"]'
> JSON.stringify({a:1, b:2}, nodeVisitor)
{"":{"a":1,"b":2}} # "" # {"a":1,"b":2}
{"a":1,"b":2} # "a" # 1
{"a":1,"b":2} # "b" # 2
'{"a":1,"b":2}'
> JSON.stringify('abc', nodeVisitor)
{"":"abc"} # "" # "abc"
'"abc"'> JSON.parse('["a","b"]', nodeVisitor)
["a","b"] # "0" # "a"
["a","b"] # "1" # "b"
{"":["a","b"]} # "" # ["a","b"]
[ 'a', 'b' ]
> JSON.parse('{"a":1, "b":2}', nodeVisitor)
{"a":1,"b":2} # "a" # 1
{"a":1,"b":2} # "b" # 2
{"":{"a":1,"b":2}} # "" # {"a":1,"b":2}
{ a: 1, b: 2 }
> JSON.parse('"hello"', nodeVisitor)
{"":"hello"} # "" # "hello"
'hello'