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

Jas*_*n S 161 javascript json ecma262

知道为什么JSON遗漏了NaN和+/- Infinity?它将Javascript放在奇怪的情况下,否则,如果它们包含NaN或+/-无穷大值,那么否则可以序列化的对象不会.

看起来像是一成不变的:见RFC4627ECMA-262(第24.3.2节,JSON.stringify,第4节,第507页,最后编辑):

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

oll*_*iej 87

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

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

NaN={valueOf:function(){ do evil }};
Infinity={valueOf:function(){ do evil }};
Run Code Online (Sandbox Code Playgroud)

进入一个论坛(或其他),然后该网站上的任何json使用可能会受到损害.

  • @olliej:你认为NaN不是文字,我不知道Javascript足以判断javascript的语义.但对于存储双精度浮点数的文件格式,应该有一种方法来定义IEEE浮点数,即通过文字NaN/Infinity/NegInfinity.这些是64位双精度的状态,因此应该是可表示的.有些人依赖他们(原因).它们可能被遗忘了,因为JSON/Javascript起源于Web开发而不是科学计算. (31认同)
  • 对于JSON来说,任意省略NaN,Infinity和-Infinity的完全有效和标准浮点数状态是100%,绝对错误.从本质上讲,JSON决定支持IEEE浮点值的任意子集,无意中省略了三个特定值,因为它们很难或者什么的.不,Eval-ability甚至不是一个借口,因为这些数字可能被编码为文字1/0,1/0和0/0.它们是附加"/ 0"的有效数字,它不仅易于检测,而且实际上可以同时作为ES进行评估.别找借口. (29认同)
  • 如果你评估1/0你获得无穷大,如果你评估-1/0你得到-Infinity,如果你评估0/0你得到NaN. (27认同)
  • 关于安全性/安全性,所有一个体面的JSON解析器在转换NaN时必须要做的是产生值0/0(而不是评估符号NaN),这将返回"真正的"NaN而不管是什么符号NaN重新定义为. (14认同)
  • 但是术语"NaN"和"Infinity"是属性名称,所以String(1/0)产生一个字符串"Infinity",它只是值无穷大的字符串表示.由于文字值是ES,因此无法表示"NaN"或"Infinity" - 您必须使用表达式(例如,1/0,0/0等)或属性查找(指"无穷大")或"NaN").由于那些需要代码执行,它们不能包含在JSON中. (9认同)
  • 我喜欢你选择拒绝_Why_ NaN和Infinity不被允许的唯一答案 - JSON专门设计为ES语言的一个子集,它只允许文字,并且根据定义,任何属性访问都不是文字. (8认同)
  • 如果您使用 eval 评估属性,则任何属性都可以用来危害系统 - 它与 NaN 或 Infinity 无关。 (8认同)
  • 这是无稽之谈。无论是否允许 NaN 或 Infinity,`eval(jsonString)` 都能够妥协任何东西。`eval("alert('1')") 不是有效的 json,但可以工作甚至没有一种方法可以在 json 中表达 `function()`。这只是对 eval 的误用。 (7认同)
  • 这里给出的安全论点是荒谬的.如果某人有权按照答案中的描述注入javascript,那么访问该网站的人会担心更大的安全问题. (6认同)
  • 此外,如果不支持最基本的除法数学运算的三个明确定义的结果,JSON不能声称支持IEEE754浮点数,更糟糕的是,它甚至没有理由这么说.与标准脱离也没有任何好处,因为即使这样做可能允许任意大数......它不仅在实践中无用(祝你把非标准数字推入任何实际变量并用它做任何事情......也可以在这一点上使用带有自定义解析器的字符串),但它将永远保持不足. (6认同)
  • 你在讨论错误的事情.JSON不应该是'eval`'d.JavaScript包含内部`NaN`和`Inf​​inity` /`-Infinity`对象.这个答案没有说明为什么Crockford不会简单地指定JSON可以使用这些表达式对这些内部对象进行编码. (4认同)
  • @OrestisP。因此,请注意,当我写这个答案时,JSON.parse 并不是普遍可用的。json 最初解析的方式本质上是 eval() 或各种脚本 (json.js),它们在将字符串传递给 ... eval 之前尝试过滤/正则表达式匹配字符串。这决定了 JSON 如何作为“规范”而开始存在。 (4认同)
  • @wirrbel,我完全同意这些值应该可以在JSON中表示.至于代码执行问题:如果解析JSON的代码之前已经与NaN混淆,那么程序员决定改变它.这不是"远程执行漏洞".至少不超过:`String.prototype.indexOf = function(){throw new Error('Crash!')};`在某个时刻跟着`obj = JSON.parse(remoteString); alert((obj.丙|| "")的indexOf( 'OK'));`.再一次,它是程序员决定搞乱`String`类,而JSON只是_refers_它,但没有决定它做什么. (3认同)
  • 好吧,如果有人可以注入任何代码,javascript使用会受到影响...... (3认同)
  • 尝试运行jsdb或Firebug控制台:NaN = {toString:function(){return"fiddledeedee"}}然后运行0/0你得到内部NaN对象; 无法重新定义它. (2认同)
  • NaN和Infinity不是属性名称(也许它们在IE的JScript中). (2认同)
  • 需要与"eval"相同的结果似乎是对JSON放置自身的愚蠢限制.即使在JSON上,也不应该使用`eval`.结果是,在某些情况下,如果不跳过篮球,你就无法做你真正需要的事情.关于JSON的最好的部分之一是它在很大程度上避免了跳过箍来传递你的数据.JSON是一种数据交换格式(也是一种非常好的格式!),它广泛用于*许多*编程语言中.除了JavaScript之外,语言的`eval`功能怎么样?它应该试图支持那些吗? (2认同)
  • JSON不是ES的子集,eval和JSON.parse在某些情况下已经给出了不同的结果.值得注意的是,JSON允许字符串中的原始`\ u2028`和`\ u2029`字符,但Ecmascript不允许. (2认同)
  • 我已经阅读了大部分 ECMAScript 规范,当然,我也了解 NaN 和 Infinity,但我刚刚了解到“未定义”实际上是全局对象的一个​​属性,我绝对感到困惑。 (2认同)

小智 54

在最初的问题上:我同意用户"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特别适合十进制,所以如果某些标准将它固定为二进制,那将是一个遗憾. (5认同)
  • @AdrianRatnapala +1确实:JSON数字具有潜在的无限精度,因此它们比IEEE规范要好得多,因为它们没有大小限制,没有精度限制,也没有舍入效果(如果序列化器可以处理它). (4认同)
  • 不管你喜欢与否,NaN 和 Infinity 是每个处理器都支持的完全有效的浮点数。如果 JSON 不支持它们,那么每个用户每次尝试在 JSON 中对浮点数进行编码时都被迫处理这个问题。 (4认同)
  • @ArnaudBouchez。也就是说,JSON应该仍然支持代表NaN和+ -Infinity的字符串。即使不应该将JSON固定为任何IEEE格式,定义数字格式的人们也应该至少查看Wikipedia页面IEEE754并停下来思考一下。 (2认同)
  • 这并不不幸。请参阅@CervEd 的答案。它与 IEE754 无关,这是一件好事(即使大多数编程语言使用 IEEE754,因此在 NaN 等情况下需要额外处理)。 (2认同)

Zoi*_*erg 16

你可以调整空对象模式,并在你的JSON中表示这样的值

"myNum" : {
   "isNaN" :false,
   "isInfinity" :true
}
Run Code Online (Sandbox Code Playgroud)

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

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

我知道在Java中你可以覆盖序列化方法以实现这样的事情.不确定序列化的位置,所以我不能详细介绍如何在序列化方法中实现它.

  • 嗯...这是解决方法的答案;我并不是真正要求解决方法,而是询问为什么这些值被排除在外。但无论如何+1。 (2认同)
  • @Zoidberg:`undefined`不是关键字,它是全局对象的属性 (2认同)
  • @Zoidberg:未定义是全局对象上的属性 - 它不是一个关键字,所以`"未定​​义"在this`在全球范围内返回true.这也意味着你可以做`undefined = 42`和`if(myVar == undefined)`变成(基本上)`myVar == 42`.这可以追溯到ECMAScript的东东JavaScript的初期其中`undefined`不存在默认情况下,于是人们就在全球范围内做了`变种undefined`.因此,在不破坏现有网站的情况下,"undefined"无法成为关键字,因此我们注定有时候将undefined作为普通属性. (2认同)
  • @olliej:我不知道为什么你认为undefined是全局对象的属性.默认情况下,undefined的查找是undefined的内置值.如果使用"undefined = 42"覆盖它,那么当您将undefined作为变量查找进行访问时,您将获得被覆盖的值.但是尝试做"zz = undefined; undefined = 42; x = {};'undefined old ='+(xa === zz)+',undefined new ='+(xa === undefined)".您永远不能重新定义null,undefined,NaN或Infinity的内部值,即使您可以覆盖它们的符号查找. (2认同)
  • @Jason`undefined`是一个全局属性,因为它是这样指定的.请参阅ECMAScript-262 3rd ed的15.1.1.3. (2认同)

teh*_*aus 11

字符串"Infinity"," - Infinity"和"NaN"都强制转换为JS中的预期值.所以我认为在JSON中表示这些值的正确方法是字符串.

> +"Infinity"
Infinity

> +"-Infinity"
-Infinity

> +"NaN"
NaN
Run Code Online (Sandbox Code Playgroud)

遗憾的是,JSON.stringify不会这样做.但有一种方法:

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

  • JSON值不能是算术表达式...使标准与语言文字语法分离的目的是使JSON不可序列化而不执行任何代码.不知道为什么我们不能将`NaN`和`Inf​​inity'添加为关键字值,如`true`和`false`. (3认同)

kuw*_*rty 6

如果您有权访问序列化代码,则可能将Infinity表示为1.0e + 1024.指数太大而不能表示为double,而当反序列化时,它表示为Infinity.适用于webkit,不确定其他json解析器!

  • IEEE754支持128位浮点数,因此1.0e5000更好 (3认同)
  • 无穷+ 1:P (3认同)
  • 吨:后来添加了128位.如果他们决定添加256位怎么办?然后,您将不得不添加更多的零,现有代码的行为将有所不同."无限"将永远是"无限",所以为什么不支持呢? (2认同)
  • 1,-1和0 .....完全有效/可解析的数字,只需在它们的末尾添加`/ 0`即可成为这三个特殊值。它易于解析,立即可见甚至可评估。他们还没有将其添加到标准中是不可原谅的:`{“不是数字”:0/0,“无穷大”:1/0,“负无穷大”:-1/0}`<<为什么没有?`alert(eval(“ \”非数字\“”))//有效``alert(eval(“ 1/0”))//也有效,打印'Infinity'`。 (2认同)

Cer*_*vEd 5

原因在标准 ECMA-404 The JSON Data Interchange Syntax, 1st Edition 的第 ii 页中说明

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

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

因为它非常简单,所以预计 JSON 语法永远不会改变。这为 JSON 作为基础符号提供了极大的稳定性

  • *...仅代表人类使用的数字...* 那么,使用无穷大符号的数学家、科学家、工程师和程序员不是人类吗?(Snark 的目标是标准,而不是 CervEd。) (2认同)
  • 这种解释确实没有道理。实际上,大多数编程语言中的实际程序将使用支持 NaN 和 Infinity 的浮点值。人类已经有办法写下数字并通过 JSON 相互发送。JSON 适用于计算机。根据他们的逻辑,JSON 应该只支持字符串。 (2认同)