javascript - ejemplo - JSON dejó fuera Infinity y NaN; Estado de JSON en ECMAScript?
string to json javascript (8)
¿Podría adaptar el patrón de objeto nulo y en su JSON representar valores tales como
"myNum" : {
"isNaN" :false,
"isInfinity" :true
}
Luego, cuando revise, puede verificar el tipo
if (typeof(myObj.myNum) == ''number'') {/* do this */}
else if (myObj.myNum.isNaN) {/* do that*/}
else if (myObj.myNum.isInfinity) {/* Do another thing */}
Sé que en Java puede anular los métodos de serialización para implementar tal cosa. No estoy seguro de dónde se serializa, por lo que no puedo dar detalles sobre cómo implementarlo en los métodos de serialización.
¿Alguna idea de por qué JSON omitió NaN y +/- Infinity? Pone Javascript en la extraña situación donde los objetos que de otro modo serían serializables, no lo son, si contienen valores de NaN o +/- infinito.
Parece que esto ha sido RFC4627 en piedra: vea RFC4627 y ECMA-262 (sección 24.3.2, JSON.stringify, NOTA 4, página 507 en la última edición):
Los números finitos se vuelven a codificar como si llamaran a
ToString(number)
. NaN e Infinity independientemente del signo se representan como Stringnull
.
El estándar actual IEEE Std 754-2008 incluye definiciones para dos representaciones de coma flotante de 64 bits diferentes: un tipo decimal de coma flotante de 64 bits y un tipo binario de coma flotante de 64 bits.
Después de redondear la cadena .99999990000000006
es lo mismo que .9999999
en la representación binaria IEEE de 64 bits, pero NO es lo mismo que .9999999
en la representación decimal IEEE de 64 bits. En el punto decimal flotante IEEE de 64 bits .99999990000000006
redondea al valor .9999999000000001
que no es el mismo que el valor decimal de .9999999
.
Como JSON solo trata los valores numéricos como cadenas numéricas de dígitos decimales, no hay forma de que un sistema que admita tanto representaciones binarias IEEE como flotantes decimales (como IBM Power) determine cuál de los dos posibles valores numéricos flotantes IEEE es destinado a.
Las cadenas "Infinity", "-Infinity" y "NaN" coaccionan a los valores esperados en JS. Entonces, argumentaría que la forma correcta de representar estos valores en JSON es como cadenas.
> +"Infinity"
Infinity
> +"-Infinity"
-Infinity
> +"NaN"
NaN
Es una pena que JSON.stringify no haga esto de forma predeterminada. Pero, hay una manera:
> JSON.stringify({ x: Infinity }, function (k,v) { return v === Infinity ? "Infinity" : v; })
"{"x":"Infinity"}"
Podría ser porque JSON está destinado a ser un formato de intercambio de datos que se puede usar en una variedad de plataformas y permitir que NaN / Infinity lo haga menos portátil.
Si tiene acceso al código de serialización, puede representar Infinity como 1.0e + 1024. El exponente es demasiado grande para representarlo en un doble y cuando se deserializa, se representa como Infinito. ¡Funciona en webkit, no está seguro de otros analizadores json!
Si, como yo, no tiene control sobre el código de serialización, puede tratar con los valores de NaN reemplazándolos por nulo o cualquier otro valor como un truco de la siguiente manera:
$.get("file.json", theCallback)
.fail(function(data) {
theCallback(JSON.parse(data.responseText.replace(/NaN/g,''null'')));
} );
En esencia, se llamará .fail cuando el analizador json original detecte un token no válido. A continuación, se utiliza una cadena de reemplazo para reemplazar los tokens no válidos. En mi caso, es una excepción que el serializador devuelva valores de NaN, por lo que este método es el mejor enfoque. Si los resultados normalmente contienen un token no válido, sería mejor no usar $ .get, sino recuperar manualmente el resultado JSON y ejecutar siempre el reemplazo de cadena.
Sobre la pregunta original: estoy de acuerdo con el usuario "cbare" en que esta es una omisión desafortunada en JSON. IEEE754 los define como tres valores especiales de un número de punto flotante. Entonces, JSON no puede representar completamente los números de coma flotante IEEE754. De hecho, es aún peor, ya que JSON, tal como se define en ECMA262 5.1, ni siquiera define si sus números se basan en IEEE754. Como el flujo de diseño descrito para la función stringify () en ECMA262 menciona los tres valores IEEE especiales, se puede sospechar que la intención era, de hecho, admitir números de punto flotante IEEE754.
Como otro punto de datos, no relacionado con la pregunta: XML datatypes xs: float y xs: double declaran que están basados en números de punto flotante IEEE754, y admiten la representación de estos tres valores especiales (Ver W3C XSD 1.0 Parte 2 , Tipos de datos).
Infinity
y NaN
no son palabras clave ni nada especial, solo son propiedades en el objeto global (como undefined
está undefined
) y, como tales, se pueden cambiar. Es por eso que JSON no los incluye en la especificación; en esencia, cualquier cadena JSON verdadera debe tener el mismo resultado en EcmaScript si eval(jsonString)
o JSON.parse(jsonString)
.
Si se permitiera, alguien podría inyectar código similar a
NaN={valueOf:function(){ do evil }};
Infinity={valueOf:function(){ do evil }};
en un foro (o lo que sea) y luego cualquier uso JSON en ese sitio podría verse comprometido.