JSON hat Infinity und NaN weggelassen; JSON-Status in ECMAScript?

Irgendeine Idee, warum JSON NaN und +/- Unendlichkeit ausließ? Es bringt Javascript in die seltsame Situation, wo Objekte, die sonst serialisierbar wären, nicht sind, wenn sie NaN- oder +/- Unendlichkeitswerte enthalten.

Sieht so aus, als ob dies in Stein gemeißelt wäre: siehe RFC4627 und ECMA-262 (Abschnitt 24.3.2, JSON.stringify, NOTE 4, Seite 507 bei der letzten Bearbeitung):

Endliche Zahlen werden wie durch den Aufruf von ToString(number) . NaN und Infinity werden unabhängig vom Vorzeichen als String null .

Infinity und NaN sind keine Schlüsselwörter oder etwas Spezielles, sie sind nur Eigenschaften auf dem globalen Objekt (wie undefined ) und können daher geändert werden. Aus diesem Grund schließt JSON sie nicht in die Spezifikation ein – im Wesentlichen sollte jede echte JSON-Zeichenfolge in EcmaScript dasselbe Ergebnis haben, wenn Sie eval(jsonString) oder JSON.parse(jsonString) .

Wenn es erlaubt wäre, könnte jemand Code ähnlich dem Code injizieren

 NaN={valueOf:function(){ do evil }}; Infinity={valueOf:function(){ do evil }}; 

in ein Forum (oder was auch immer) und dann könnte jede Json-Nutzung auf dieser Seite kompromittiert werden.

Auf der ursprünglichen Frage: Ich stimme dem Benutzer “cbare” darin zu, dass dies eine unglückliche Unterlassung in JSON ist. IEEE754 definiert diese als drei spezielle Werte einer Fließkommazahl. JSON kann IEEE754-Fließkommazahlen also nicht vollständig darstellen. Es ist sogar noch schlimmer, da JSON, wie in ECMA262 5.1 definiert, nicht einmal definiert, ob seine Nummern auf IEEE754 basieren. Da der für die stringify () -function in ECMA262 beschriebene Entwurfsablauf die drei speziellen IEEE-Werte erwähnt, kann man vermuten, dass die Absicht darin bestand, IEEE754-Fließkommazahlen zu unterstützen.

Als ein weiterer Datenpunkt, der nichts mit der Frage zu tun hat: Die XML-Datentypen xs: float und xs: double geben an, dass sie auf IEEE754-Gleitkommazahlen basieren und unterstützen die Darstellung dieser drei speziellen Werte (Siehe W3C XSD 1.0 Teil 2 , Datentypen).

Könnten Sie das Null-Objektmuster anpassen und in Ihrem JSON solche Werte wie

 "myNum" : { "isNaN" :false, "isInfinity" :true } 

Bei der Überprüfung können Sie dann nach dem Typ suchen

 if (typeof(myObj.myNum) == 'number') {/* do this */} else if (myObj.myNum.isNaN) {/* do that*/} else if (myObj.myNum.isInfinity) {/* Do another thing */} 

Ich weiß in Java können Sie Serialisierungsmethoden überschreiben, um so etwas zu implementieren. Ich bin mir nicht sicher, woher die Serialisierung von, also kann ich nicht angeben, wie Sie es in den Serialisierungsmethoden implementieren.

Das könnte daran liegen, dass JSON ein Datenaustauschformat sein soll, das auf einer Vielzahl von Plattformen verwendet werden kann und NaN / Infinity es weniger tragbar machen würde.

Die Zeichenfolgen “Infinity”, “-Infinity” und “NaN” erzwingen die erwarteten Werte in JS. Also würde ich argumentieren, dass die richtige Art, diese Werte in JSON darzustellen, Strings sind.

 > +"Infinity" Infinity > +"-Infinity" -Infinity > +"NaN" NaN 

Es ist nur eine Schande JSON.stringify tut dies nicht standardmäßig. Aber es gibt einen Weg:

 > JSON.stringify({ x: Infinity }, function (k,v) { return v === Infinity ? "Infinity" : v; }) "{"x":"Infinity"}" 

Wenn Sie Zugriff auf den Serialisierungscode haben, könnten Sie Infinity als 1.0e + 1024 darstellen. Der Exponent ist zu groß, um in einem Doppel darzustellen, und wenn er deserialisiert wird, wird dies als Unendlichkeit dargestellt. Arbeitet auf Webkit, unsicher über andere JSON-Parser!

Die aktuelle IEEE-Norm 754-2008 enthält Definitionen für zwei verschiedene 64-Bit-Gleitkommadarstellungen: einen dezimalen 64-Bit-Gleitkommatyp und einen binären 64-Bit-Gleitkommatyp.

Nach dem Runden der Zeichenfolge .99999990000000006 ist das gleiche wie .9999999 in der IEEE-Binär-64-Bit-Darstellung, aber es ist nicht dasselbe wie .9999999 in der IEEE-Dezimal-64-Bit-Darstellung. In 64-Bit-IEEE-Dezimal-Fließkomma .99999990000000006 rundet auf den Wert .9999999000000001 die nicht das gleiche ist wie der Dezimal .9999999 Wert.

Da JSON numerische Werte nur als numerische Dezimalziffern behandelt, gibt es keine Möglichkeit für ein System, das sowohl IEEE-binäre als auch dezimale Gleitkommadarstellungen (wie IBM Power) unterstützt, um zu bestimmen, welcher der beiden möglichen IEEE-numerischen Gleitkommawerte ist beabsichtigt.

Mögliche Problemumgehung für Fälle wie {“key”: Infinity}:

 JSON.parse(theString.replace(/":(Infinity|-InNaN)/g, '":"{{$1}}"'), function(k, v) { if (v === '{{Infinity}}') return Infinity; else if (v === '{{-Infinity}}') return -Infinity; else if (v === '{{NaN}}') return NaN; return v; }); 

Die allgemeine Idee besteht darin, das Auftreten ungültiger Werte durch eine Zeichenfolge zu ersetzen, die wir beim Parsen erkennen und durch die entsprechende JavaScript-Darstellung ersetzen.

Wenn Sie wie ich keine Kontrolle über den Serialisierungscode haben, können Sie mit NaN-Werten umgehen, indem Sie sie wie folgt mit null oder einem anderen Wert als Hack ersetzen:

 $.get("file.json", theCallback) .fail(function(data) { theCallback(JSON.parse(data.responseText.replace(/NaN/g,'null'))); } ); 

Im Wesentlichen wird .fail aufgerufen, wenn der ursprüngliche json-Parser ein ungültiges Token erkennt. Dann wird eine Zeichenfolge ersetzt, um die ungültigen Token zu ersetzen. In meinem Fall ist es eine Ausnahme, dass der Serialisierer NaN-Werte zurückgibt, so dass diese Methode der beste Ansatz ist. Wenn die Ergebnisse normalerweise ein ungültiges Token enthalten, wäre es besser, nicht $ .get zu verwenden, sondern das JSON-Ergebnis manuell abzurufen und immer den Zeichenfolgenaustausch auszuführen.