知道为什么JSON省略了NaN和+/- Infinity吗?它将Javascript置于一种奇怪的情况中,如果对象包含NaN或+/-无穷大值,则对象将不可序列化。

看起来这已经是铁板一块了:参见RFC4627和ECMA-262(第24.5.2节,JSON。ECMA-262 pdf最后一次编辑第683页):

有限数字被字符串化,就像调用ToString(number)一样。NaN和Infinity,无论符号是什么,都表示为字符串null。


你能适应空对象模式,并在JSON中表示这样的值吗

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

然后在检查时,可以检查类型

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

我知道在Java中,你可以重写序列化方法来实现这样的事情。不确定你的序列化从哪里来,所以我不能详细说明如何在序列化方法中实现它。


Infinity和NaN不是关键字或任何特殊的东西,它们只是全局对象上的属性(未定义),因此可以更改。正是因为这个原因,JSON没有在规范中包含它们——本质上,如果你使用eval(jsonString)或JSON.parse(jsonString),任何真正的JSON字符串在EcmaScript中都应该有相同的结果。

如果允许,那么有人可以注入类似于

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

进入一个论坛(或任何地方),然后该网站上的任何json使用都可能受到损害。


On the original question: I agree with user "cbare" in that this is an unfortunate omission in JSON. IEEE754 defines these as three special values of a floating point number. So JSON cannot fully represent IEEE754 floating point numbers. It is in fact even worse, since JSON as defined in ECMA262 5.1 does not even define whether its numbers are based on IEEE754. Since the design flow described for the stringify() function in ECMA262 does mention the three special IEEE values, one can suspect that the intention was in fact to support IEEE754 floating point numbers.

作为另一个与问题无关的数据点:XML数据类型xs:float和xs:double确实表明它们基于IEEE754浮点数,并且它们确实支持这三个特殊值的表示(参见W3C XSD 1.0第2部分,数据类型)。


如果您可以访问序列化代码,则可以将Infinity表示为1.0e+1024。指数太大,不能用双精度表示,反序列化时,它表示为无穷大。适用于webkit,不确定其他json解析器!


如果你像我一样无法控制序列化代码,你可以用null或任何其他值来处理NaN值,如下所示:

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

本质上,当原始json解析器检测到无效令牌时,.fail将被调用。然后使用字符串replace替换无效的令牌。在我的情况下,它是一个例外的序列化器返回NaN值,所以这个方法是最好的方法。如果结果通常包含无效令牌,最好不要使用$。而不是手动检索JSON结果,并始终运行字符串替换。


字符串“Infinity”、“-Infinity”和“NaN”都被强制转换为JS中的期望值。所以我认为在JSON中表示这些值的正确方法是字符串。

> +"Infinity"
Infinity

> +"-Infinity"
-Infinity

> +"NaN"
NaN

JSON太可惜了。Stringify默认情况下不这样做。但有一个办法:

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

当前的IEEE Std 754-2008包含了两种不同的64位浮点表示形式的定义:十进制64位浮点类型和二进制64位浮点类型。

在舍入字符串后,.99999990000000006与IEEE二进制64位表示中的.9999999相同,但与IEEE十进制64位表示中的.9999999不同。在64位IEEE十进制浮点数中,.99999990000000006舍入为值.9999999000000001,这与十进制值.9999999不相同。

由于JSON只是将数值视为十进制数字的数字字符串,因此同时支持IEEE二进制和十进制浮点表示的系统(如IBM Power)无法确定两个可能的IEEE数字浮点值中的哪一个是要使用的。


{"key":Infinity}等情况的潜在解决方案:

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

一般思想是用解析时可以识别的字符串替换出现的无效值,然后用适当的JavaScript表示替换回来。


原因在标准ECMA-404 JSON数据交换语法第1版的第2页说明

JSON is agnostic about numbers. In any programming language, there can be a variety of number types of various capacities and complements, fixed or floating, binary or decimal. That can make interchange between different programming languages difficult. JSON instead offers only the representation of numbers that humans use: a sequence of digits. All programming languages know how to make sense of digit sequences even if they disagree on internal representations. That is enough to allow interchange.

原因并不像许多人声称的那样,是由于NaN和Infinity ECMA脚本的表示。简单性是JSON的核心设计原则。

因为它非常简单,所以JSON语法不会发生任何变化。这为JSON(作为一种基本表示法)提供了极大的稳定性


JSON5允许使用标准的Javascript符号来表示正无穷大和负无穷大、NaN以及许多其他在JSON中被省略的有效ECMAScript(后面的逗号等)。

https://json5.org/

这使得JSON成为一种更有用的格式。

然而,无论是使用JSON还是JSON5:出于安全原因,总是总是解析——不要计算!!