JSON省略了Infinity和NaN;JSON在ECMAScript中的状态?

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

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

有限数被字符串化,就像调用ToString(number)一样。和Infinity(不考虑符号)表示为字符串null

91164 次浏览

你能适应空对象模式,并在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中,你可以重写序列化方法来实现这样的事情。不确定你的序列化从哪里来,所以我不能详细说明如何在序列化方法中实现它。

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

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

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

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

关于最初的问题:我同意用户“cbare”的观点,这是JSON中一个不幸的遗漏。IEEE754将它们定义为浮点数的三个特殊值。因此JSON不能完全表示IEEE754浮点数。实际上情况更糟,因为ECMA262 5.1中定义的JSON甚至没有定义其数字是否基于IEEE754。由于ECMA262中描述的stringify()函数的设计流程确实提到了三个特殊的IEEE值,因此可以怀疑其意图实际上是支持IEEE754浮点数。

作为另一个与问题无关的数据点: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位表示中的相同。在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数据交换语法第一版的第二页中说明

JSON与数字无关。在任何编程语言中,都可以有各种容量和补数的各种数字类型,固定或浮动,二进制或十进制。这可能会使不同编程语言之间的交换变得困难。相反,JSON只提供人类使用的数字表示:数字序列。所有编程语言都知道如何理解数字序列,即使它们在内部表示上存在分歧。这就足够允许交换了。

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

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

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

< a href = " https://json5.org/ " rel = " noreferrer > https://json5.org/ < / >

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

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