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

IT技术 javascript json ecma262
2021-01-27 14:08:10

知道为什么 JSON 会遗漏 NaN 和 +/- Infinity 吗?它将 Javascript 置于奇怪的情况下,如果它们包含 NaN 或 +/- 无穷大值,则本来可以序列化的对象不是。

看起来这已经是一成不变的:见RFC4627ECMA-262(上次编辑时 ECMA-262 pdf 的第 24.5.2 节,JSON.stringify,注释 4,第 683 页):

有限数被字符串化,就像通过调用ToString(number). NaN和 Infinity 无论符号如何都表示为 String null

6个回答

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

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

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 部分, 数据类型)。

我同意这一切都是不幸的。但也许 JSON 数字没有指定确切的浮点格式是一件好事。甚至 IEEE754 也指定了许多格式——不同的大小,以及十进制和二进制指数之间的区别。JSON 特别适合十进制,因此如果某些标准将其固定为二进制,那就太可惜了。
2021-03-24 14:08:10
@ArnaudBouchez。也就是说,JSON 应该仍然支持表示 NaN 和 +-Infinity 的字符串。即使 JSON 不应该被固定到任何 IEEE 格式,定义数字格式的人至少应该看看维基百科页面 IEEE754 并停下来思考一下。
2021-03-24 14:08:10
这并不不幸。请参阅@CervEd 的答案。它与 IEE754 无关,这是一件好事(即使大多数编程语言使用 IEEE754,因此在 NaN 等情况下需要额外处理)。
2021-04-02 14:08:10
@AdrianRatnapala +1 事实上:JSON 数字具有潜在的无限精度,因此比 IEEE 规范要好得多,因为它们没有大小限制、精度限制和舍入效果(如果序列化程序可以处理的话)。
2021-04-11 14:08:10

你能不能适应空对象模式,并在你的 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 中你可以覆盖序列化方法来实现这样的事情。不确定您的序列化来自何处,因此我无法详细说明如何在序列化方法中实现它。

嗯……这是解决方法的答案;我并不是真的在寻求解决方法,而是为什么要排除这些值。但无论如何+1。
2021-03-15 14:08:10
@olliej:我不知道你为什么认为 undefined 是全局对象的一个​​属性。默认情况下,undefined 的查找是 undefined 的内置值。如果您使用“undefined=42”覆盖它,那么当您访问 undefined 作为变量查找时,您将获得覆盖的值。但是尝试做“zz=undefined; undefined=42; x={}; 'undefined old='+(xa === zz)+', undefined new='+(xa === undefined)”。您永远不能重新定义 null、undefined、NaN 或 Infinity 的内部值,即使您可以覆盖它们的符号查找。
2021-03-31 14:08:10
@Zoidberg:undefined不是关键字,而是全局对象上的属性
2021-04-04 14:08:10
@Zoidberg:undefined 是全局对象上的一个属性——它不是关键字,因此"undefined" in this在全局范围内返回 true。这也意味着你可以做undefined = 42if (myVar == undefined)成为(本质上)myVar == 42这可以追溯到undefined默认情况下不存在的 ecmascript nee javascript 的早期,所以人们只是var undefined在全局范围内这样做因此undefined,在不破坏现有站点的情况下无法将关键字设为关键字,因此我们注定永远将 undefined 设为正常属性。
2021-04-05 14:08:10
@Jasonundefined是一个全局属性,因为它是这样指定的。请参阅 ECMAScript-262 第 3 版的 15.1.1.3。
2021-04-12 14:08:10

字符串 "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"}"
JSON 值不能是算术表达式......使标准与语言文字语法分开的目标是使 JSON 可解序列化,而无需将其作为代码执行。不知道为什么我们不能and那样添加NaNInfinity作为关键字值truefalse
2021-03-17 14:08:10
为了使它更明确,我们可以使用Number("Infinity"),Number("-Infinity")Number("NaN")
2021-03-19 14:08:10
这就像魔术一样工作。JSON.parse("{ \"value\" : -1e99999 }")很容易{ value:-Infinity }在javascript中返回只有它与可能大于此的自定义数字类型不兼容
2021-03-31 14:08:10
相反,我认为这是唯一实用的解决方案,但我会做一个函数,如果输入值为“NaN”,则返回 NaN,等等。您进行转换的方式容易出现代码注入。
2021-04-05 14:08:10
0/0 等不是有效的 JSON。你必须在标准的范围内工作,字符串可以很好地完成这项工作。
2021-04-13 14:08:10

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

IEEE754 支持 128 位浮点数,所以 1.0e5000 更好
2021-03-25 14:08:10
Ton:128 位是后来添加的。如果他们决定添加 256 位怎么办?然后你必须添加更多的零,现有代码的行为会有所不同。Infinity将永远是Infinity,那么为什么不支持呢?
2021-03-30 14:08:10
1、-1 和 0..... 完全有效/可解析的数字,当您简单地添加/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'. 别找借口。
2021-04-11 14:08:10
好主意!我正要切换到不同的格式或向我的解析器添加繁琐的解决方法代码。并非对每种情况都理想,但在我的情况下,无穷大仅作为收敛序列的优化边缘情况,它只是完美的,即使引入更大的精度,它仍然大部分是正确的。谢谢!
2021-04-12 14:08:10