JSON遗漏了Infinity和NaN; ECMAScript中的JSON状态?

任何想法为什么JSON遗漏NaN和+/- Infinity? 它把JavaScript放在奇怪的情况下,否则这些对象可能是可序列化的,如果它们包含NaN或+/-无穷大值,则不是。

看起来像这样被扔石头:见RFC4627和ECMA-262 (24.3.2,JSON.stringify,注4,在最后编辑页507):

有限数字通过调用ToString(number)进行string化。 无论符号如何, NaN和Infinity都表示为String null

InfinityNaN不是关键字或任何特殊的东西,它们只是全局对象的属性(因为是undefined ),因此可以改变。 正是出于这个原因,JSON并没有将它们包含在规范中 – 实际上,如果您使用eval(jsonString)JSON.parse(jsonString)则任何真正的JSONstring都应该在EcmaScript中具有相同的结果。

如果允许,那么有人可以注入类似的代码

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

到一个论坛(或其他),然后在该网站上的任何JSON使用可能会受到影响。

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

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

你可以适应空对象模式,并在您的JSON代表像这样的值

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

然后在检查时,可以检查types

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

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

这可能是因为JSON旨在成为一种数据交换格式,可用于各种平台,并允许NaN / Infinity降低其便携性。

如果您有权访问序列化代码,则可以将Infinity表示为1.0e + 1024。 指数太大,不能用双精度表示,反序列化时用无穷大表示。 在webkit上工作,不确定其他jsonparsing器!

string“Infinity”,“-Infinity”和“NaN”都强制JS中的期望值。 所以我认为在JSON中表示这些值的正确方法是string。

 > +"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位浮点types和二进制64位浮点types。

四舍五入后的string.99999990000000006与IEEE二进制64位表示中的.9999999相同, .9999999与IEEE十进制64位表示中的.9999999 。 在64位IEEE十进制浮点数.99999990000000006入值为.9999999000000001 ,这与十进制的.9999999值不一样。

由于JSON仅将数字值视为十进制数字的数字string,因此无法同时支持IEEE二进制和十进制浮点表示(例如IBM Power)的系统来确定两个可能的IEEE数字浮点值中的哪一个意。

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

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

实质上,当原始jsonparsing器检测到一个无效标记时,.fail将被调用。 然后使用stringreplacereplace无效令牌。 在我的情况下,这是serialiser返回NaN值的例外,所以这个方法是最好的方法。 如果结果通常包含无效标记,则最好不要使用$ .get,而是手动检索JSON结果并始终运行stringreplace。