为啥 JSON.parse(['1234']) 返回 1234?

Posted

技术标签:

【中文标题】为啥 JSON.parse([\'1234\']) 返回 1234?【英文标题】:Why does JSON.parse(['1234']) return 1234?为什么 JSON.parse(['1234']) 返回 1234? 【发布时间】:2017-09-28 19:19:31 【问题描述】:

我无法理解JSON.parse 的行为。 JSON.parse 应该只适用于字符串。但它似乎适用于只包含一个字符串(甚至单引号)的数组,如果字符串只包含数字。

JSON.parse(['1234']) // => 1234
JSON.parse(['1234as']) // => throws error
JSON.parse(['123', '123']) // => throws error

【问题讨论】:

我知道它们都不是有效的 JSON。但是 JSON.parse 应该抛出错误,正如我在第一种情况下所期望的那样,但事实并非如此。 不要参考 w3schools 来理解 JSON。我刚刚审查了它,它在很多方面都非常错误。 另外,我认为 Solomonoff 的意思是“这是 javascript。您应该期望它符合 ECMAScript 规范,该规范准确解释了当您将非字符串传递给需要字符串的函数时会发生什么" 仅供参考:“即使是单引号”在这里也没有相关性。 JavaScript 字符串周围的单引号和双引号与其作为 JSON 的有效性无关。 @TravisJ 你对什么是 JavaScript 和什么是 JSON 感到困惑。 JavaScript 字符串周围的引号在您的示例中无关紧要,并且您为两个示例都选择了单引号,完全忽略了这一点。 JavaScript 字符串中的引号 inside 是编码 JSON 的一部分,绝对重要,我从未表示它们不重要。 在 JavaScript 中用于创建字符串文字的引号不会影响该字符串中的字符是否是有效的 JSON;解析 '"foo"'"\"foo\"" 没有区别,它们实际上是相同的字符串。 【参考方案1】:

这里需要注意两点:

1) JSON.parse 将参数转换为字符串(参考规范中算法的第一步)。您的输入结果如下:

['1234']       // String 1234
['1234as']     // String 1234as
['123', '123'] // String 123,123

2) json.org 的规范声明:

[...] 值可以是双引号中的字符串、数字或 true 或 false 或 null,或对象或数组。这些结构可以 嵌套。

所以我们有:

JSON.parse(['1234'])
// Becomes JSON.parse("1234")
// 1234 could be parsed as a number
// Result is Number 1234 

JSON.parse(['1234as'])
// Becomes JSON.parse("1234as")
// 1234as cannot be parsed as a number/true/false/null
// 1234as cannot be parsed as a string/object/array either
// Throws error (complains about the "a")

JSON.parse(['123', '123'])
// Becomes JSON.parse("123,123")
// 123 could be parsed as a number but then the comma is unexpected
// Throws error (complains about the ",")

【讨论】:

【参考方案2】:

正如您所指出的,JSON.parse() 需要一个字符串而不是一个数组。但是,当给定一个数组或任何其他非字符串值时,该方法将自动将其强制转换为一个字符串并继续而不是立即抛出。来自spec:

    让 JText 为 ToString(text)。 ...

数组的字符串表示形式由其值组成,以逗号分隔。所以

String(['1234']) 返回'1234'String(['1234as']) 返回'1234as',并且 String(['123', '123']) 返回'123,123'

请注意,字符串值不再被引用。这意味着['1234'][1234] 都转换为相同的字符串'1234'

所以你真正在做的是:

JSON.parse('1234')
JSON.parse('1234as')
JSON.parse('123,123')

1234as123,123 不是有效的 JSON,因此JSON.parse() 在这两种情况下都会抛出。 (前者从一开始就不是合法的 JavaScript 语法,而后者包含不属于的逗号运算符。)

1234 另一方面是数字文字,因此是有效的 JSON,代表它自己。这就是为什么JSON.parse('1234')(以及扩展名JSON.parse(['1234']))返回数值1234的原因。

【讨论】:

"..是数字文字,因此是有效的 JSON.." - 单个数字文字不是有效的 JSON,但 JSON.parse 不是很严格 (具体来说,它解析 JSON 对象和单个值)。请参阅here 了解更多信息。 @BlueRaja-DannyPflughoeft 我关注了你的链接。不同意你的结论。如果“有效的 JSON”是指“有效的 JSON 文本”,那么单个数字文字过去是无效的,但现在是有效的。此外,“有效 JSON”具有除“有效 JSON 文本”之外的其他有效解释,并且根据其他一些解释,单个数字文字始终有效。 可以通过JSON.parse(['[123', '123]']) 将其提升到一个新的水平:P @BlueRaja-DannyPflughoeft RFC 7159 和 ECMA-404 已修改 JSON 规范,以允许***值是数字或字符串,而不仅仅是对象或数组。 JSON.parse() 与此更改一致。 @BlueRaja-DannyPflughoeft:不幸的是,JSON 有多个版本。 Doug Crockford 在JSON.org 上发布了原始版本。但 JSON 也有两个国际标准,即ECMA-404(取代section 15.12.1 of ECMA-262 5.1 Edition 中的规范)和RFC 7159(取代RFC 4627)。还有……【参考方案3】:

如果 JSON.parse 没有得到字符串,它会首先将输入转换为字符串。

["1234"].toString() // "1234"
["1234as"].toString() // "1324as"
["123","123"].toString() // "123,123"

从所有这些输出中,它只知道如何解析“1234”。

【讨论】:

以上是关于为啥 JSON.parse(['1234']) 返回 1234?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 JSON.parse(decodeURIComponent(staticString))?

为啥使用 JSON.parse(decodeURIComponent(staticString))?

为啥 JSON.parse 会抛出跨域错误?

JSON.parse(message) 失败,但“https://jsonlint.com/”显示消息有效。为啥会这样?

json数组原始字符串

COCOS2D - JS 之JSON 解析