知道为什么JSON遗漏了NaN和+/- Infinity吗?如果它们包含NaN或+/-无穷大值,则Javascript处于一种奇怪的情况下,否则本来可以序列化的对象就无法实现。
看起来像是一成不变的:请参阅RFC4627和ECMA-262(第24.5.2节,JSON.stringify,注意4,最后编辑的ECMA-262 pdf第683页):
有限数字被字符串化,好像通过调用
ToString(number)
。NaN和Infinity(不考虑符号)均表示为Stringnull
。
知道为什么JSON遗漏了NaN和+/- Infinity吗?如果它们包含NaN或+/-无穷大值,则Javascript处于一种奇怪的情况下,否则本来可以序列化的对象就无法实现。
看起来像是一成不变的:请参阅RFC4627和ECMA-262(第24.5.2节,JSON.stringify,注意4,最后编辑的ECMA-262 pdf第683页):
有限数字被字符串化,好像通过调用
ToString(number)
。NaN和Infinity(不考虑符号)均表示为Stringnull
。
Answers:
Infinity
并且NaN
不是关键字或任何特殊内容,它们只是全局对象的属性(按原样undefined
),因此可以更改。因此,JSON不在规范中包含它们-本质上,如果您使用eval(jsonString)
或,则任何真正的JSON字符串在EcmaScript中都应具有相同的结果JSON.parse(jsonString)
。
如果允许,那么有人可以注入类似于
NaN={valueOf:function(){ do evil }};
Infinity={valueOf:function(){ do evil }};
进入论坛(或其他),然后该网站上的任何json使用情况都可能受到影响。
NaN
和Infinity
是属性名称,因此String(1/0)生成的字符串"Infinity"
只是值无穷大的字符串表示形式。ES 既不能代表它,也不能代表它NaN
,Infinity
因为您必须使用表达式(例如1 / 0、0 / 0等)或属性查找(引用Infinity
或NaN
)。由于那些需要执行代码,因此它们不能包含在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部分) ,数据类型)。
您能否适应空对象模式,并在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中,您可以重写序列化方法以实现这样的事情。不知道从何处进行序列化,因此我无法提供有关如何在序列化方法中实现的详细信息。
undefined
不是关键字,它是全局对象的属性
"undefined" in this
在全局范围内返回true。这也意味着您可以做到undefined = 42
并if (myVar == undefined)
(基本上)成为myVar == 42
。这可以追溯到ecmascript nee javascript的早期undefined
,默认情况下不存在,因此人们只是var undefined
在全球范围内这样做。因此undefined
,在不破坏现有站点的情况下就不能成为关键字,因此我们注定要一直将undefined定义为常规属性。
undefined
是全局属性,因为它是这样指定的。请参阅ECMAScript-262第3版的15.1.1.3。
字符串“ 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"}"
NaN
其Infinity
添加为关键字值,例如true
和false
。
Number("Infinity")
,Number("-Infinity")
并且Number("NaN")
JSON.parse("{ \"value\" : -1e99999 }")
轻松返回{ value:-Infinity }
javascript。只有它与可能更大的自定义数字类型不兼容
如果您有权访问序列化代码,则可以将Infinity表示为1.0e + 1024。指数太大,无法以双精度表示,反序列化时表示为无穷大。可在webkit上使用,不确定其他json解析器!
Infinity
会一直Infinity
如此,那为什么不支持呢?
/0
到它们的末尾时,就成为这三个特殊值。它易于解析,立即可见甚至可评估。他们尚未将其添加到标准中是不可原谅的:{"Not A Number":0/0,"Infinity":1/0,"Negative Infinity":-1/0}
<<为什么不呢? alert(eval("\"Not A Number\"") //works
alert(eval("1/0")) //also works, prints 'Infinity'
。别找借口。
当前的IEEE Std 754-2008包括两种不同的64位浮点表示形式的定义:十进制64位浮点类型和二进制64位浮点类型。
舍入后的字符串.99999990000000006
相同.9999999
的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第1版JSON数据交换语法的第ii页中进行了说明
JSON与数字无关。在任何编程语言中,可以有各种容量和补码形式的数字类型,固定或浮动,二进制或十进制。这会使不同编程语言之间的交换变得困难。JSON而是仅提供人类使用的数字表示形式:数字序列。所有编程语言都知道如何理解数字序列,即使它们在内部表示形式上存在分歧。这足以允许互换。
正如许多人所声称的,原因并不是由于NaN
和Infinity
ECMA脚本的表示。简单性是JSON的核心设计原则。
因为它是如此简单,所以JSON语法不会发生变化。作为基本符号,这为JSON提供了极大的稳定性
如果像我一样您无法控制序列化代码,则可以通过将NaN值替换为null或任何其他值来处理NaN值,如下所示:
$.get("file.json", theCallback)
.fail(function(data) {
theCallback(JSON.parse(data.responseText.replace(/NaN/g,'null')));
} );
本质上,当原始json解析器检测到无效令牌时,将调用.fail。然后使用字符串替换来替换无效令牌。在我的情况下,序列化程序返回NaN值是一个例外,因此此方法是最好的方法。如果结果通常包含无效令牌,则最好不要使用$ .get,而应手动检索JSON结果并始终运行字符串替换。
{ "tune": "NaNaNaNaNaNaNaNa BATMAN", "score": NaN }