web-dev-qa-db-fra.com

JSON a laissé Infinity et NaN; Statut JSON dans ECMAScript?

Aucune idée pourquoi JSON a laissé NaN et +/- Infinity? Cela place Javascript dans la situation étrange où des objets qui autrement seraient sérialisables ne le sont pas s'ils contiennent des valeurs NaN ou +/- infinity.

On dirait que tout est dans la pierre: voir RFC4627 et ECMA-262 (section 24.3.2, JSON.stringify, NOTE 4, page 507 lors de la dernière modification):

Les nombres finis sont chaînés comme en appelant ToString(number). NaN et l'infini quel que soit le signe sont représentés par la chaîne null.

155
Jason S

Infinity et NaN ne sont ni des mots-clés ni rien de spécial, ce ne sont que des propriétés sur l'objet global (tel que undefined) et peuvent donc être modifiés. C’est pour cette raison que JSON ne les inclut pas dans la spécification - en principe, toute chaîne JSON vraie devrait avoir le même résultat dans EcmaScript si vous faites eval(jsonString) ou JSON.parse(jsonString).

Si cela était autorisé, quelqu'un pourrait injecter du code semblable à

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

dans un forum (ou autre) et toute utilisation de JSON sur ce site pourrait être compromise.

84
olliej

Sur la question initiale: je suis d’accord avec l’utilisateur "cbare" en ce sens qu’il s’agit d’une omission regrettable dans JSON. IEEE754 les définit comme trois valeurs spéciales d’un nombre à virgule flottante. JSON ne peut donc pas représenter complètement les nombres à virgule flottante IEEE754. C'est en fait encore pire, puisque JSON tel que défini dans ECMA262 5.1 ne définit même pas si ses numéros sont basés sur IEEE754. Étant donné que le flux de conception décrit pour la fonction stringify () dans ECMA262 mentionne bien les trois valeurs IEEE spéciales, on peut penser que l'intention était en réalité de prendre en charge les nombres à virgule flottante IEEE754.

Comme un autre point de données, non lié à la question: Les types de données XML xs: float et xs: double do indiquent qu'ils sont basés sur des nombres à virgule flottante IEEE754 et qu'ils prennent en charge la représentation de ces trois valeurs spéciales (voir W3C XSD 1.0 Partie 2 , Types de données).

52
Andreas Maier

Pourriez-vous adapter le modèle d'objet null et dans votre JSON représenter des valeurs telles que

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

Ensuite, lors de la vérification, vous pouvez vérifier le type

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

Je sais que dans Java vous pouvez remplacer les méthodes de sérialisation afin de mettre en œuvre une telle chose. Vous ne savez pas d'où vient votre sérialisation, je ne peux donc pas vous donner de détails sur la façon de l'implémenter dans les méthodes de sérialisation.

15
Zoidberg

Les chaînes "Infinity", "-Infinity" et "NaN" contraignent toutes les valeurs attendues dans JS. Je dirais donc que la bonne façon de représenter ces valeurs en JSON est sous forme de chaînes.

> +"Infinity"
Infinity

> +"-Infinity"
-Infinity

> +"NaN"
NaN

C'est juste dommage que JSON.stringify ne le fasse pas par défaut. Mais il y a un moyen:

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

Si vous avez accès au code de sérialisation, vous pouvez représenter Infinity par 1.0e + 1024. L'exposant est trop grand pour être représenté dans un double et lorsqu'il est désérialisé, il est représenté par l'infini. Fonctionne sur le webkit, incertain pour les autres analyseurs JSON!

6
kuwerty

La norme actuelle IEEE 754-2008 comprend des définitions pour deux représentations différentes à virgule flottante 64 bits: un type à virgule flottante 64 bits décimal et un type binaire à virgule flottante 64 bits.

Après avoir arrondi la chaîne .99999990000000006 est le même que .9999999 dans la représentation binaire IEEE 64 bits, mais PAS identique à .9999999 dans la représentation décimale IEEE 64 bits. En virgule flottante décimale IEEE 64 bits .99999990000000006 arrondit à la valeur .9999999000000001 qui n'est pas la même chose que la décimale .9999999 valeur.

JSON considérant simplement les valeurs numériques comme des chaînes numériques de chiffres décimaux, il n’existe aucun moyen pour un système prenant en charge les représentations à virgule flottante binaires et décimales IEEE (telles que IBM Power) pour déterminer laquelle des deux valeurs à virgule flottante numériques IEEE possibles est: prévu.

1
Steven Hobbs