当键名称具有数值时,JSON.parse() 是否真的对属性进行排序?

2024-02-15

这里有很多关于这个问题的帖子,它们都包含很多断言,可以总结如下:

  1. 永远不能保证对象属性以任何方式排序。
  2. JSON.parse()从不以任何方式对属性进行排序。

显然,我们对上面的#1 没有任何疑问,因此我们可以合理地预期,对于任何操作,属性仅按照它们出现的顺序进行处理。
[编辑,遵循@Bergi的评论:或者至少它们应该以随机顺序出现]

然后我们可以特别推断#2 应该是正确的。

但看看这个片段:
(顺便说一句注意:为了显示结果,下面的代码片段不使用console.log()这本身可能会改变输出的顺序。相反,对象被迭代for (key in obj)以及文档中显示的输出)

var inputs = [
  '{"c": "C", "a": "A", "b": "B"}',
  '{"3": "C", "1": "A", "2": "B"}',
  '{"c": "C", "a": "A", "3": "C", "1": "A", "b": "B", "2": "B"}'
];

for (var i in inputs) {
  var json = inputs[i],
      parsed = JSON.parse(json),
      output = [];
  for (var j in parsed) {
    output.push(j + ': ' + parsed[j]);
  }
  document.write(`JSON: ${json}<br />Parsed: ${output.join(', ')})<hr />`);
}

它表明,给定一个具有无序键的 JSON 字符串:

  • 当输入有具有非数字值的键,解析的对象有它的相同顺序的属性比输入中的。这与上面#2 假设一致。
  • 相反,当输入有带有数值的键(虽然它们是字符串,所以不会引发解析错误),解析的对象有它的属性排序。这现在与#2 假设相矛盾。
  • 更多:当有混合数字和非数字键值,首先出现的是数字属性已排序,那么按原始顺序排列的非数字属性.

由此我首先想得出结论,实际上会有一个(未记录的?)功能,所以JSON.parse()遵循上面公开的“规则”进行工作。

但我想进一步了解,因此下面的代码片段现在显示了仅编码对象的属性的排序方式:

var objects = [
  [
    '{"c": "C", "a": "A", "b": "B"}',
    {"c": "C", "a": "A", "b": "B"}
  ],
  [
    '{"3": "C", "1": "A", "2": "B"}',
    {"3": "C", "1": "A", "2": "B"}
  ],
  [
    '{"c": "C", "a": "A", "3": "C", "1": "A", "b": "B", "2": "B"}',
    {"c": "C", "a": "A", "3": "C", "1": "A", "b": "B", "2": "B"}
  ]
];

for (var i in objects) {
  var object = objects[i],
      output = [];
  for (var j in object[1]) {
    output.push(j + ': ' + object[1][j]);
  }
  document.write(`Code: ${object[0]}<br />Object: ${output.join(', ')}<hr />`);
}

它会产生模拟观察结果,即无论它们的编码顺序如何,属性都按照上面的第三条规则存储:

  • 数字命名的属性都放在前面,排序
  • 接下来设置其他属性,按编码排序

所以这意味着JSON.parse()没有涉及:实际上这似乎是对象构建的基本过程。
同样,这似乎没有记录,至少据我所知。

关于真正的、权威的规则有什么线索吗?


[编辑,感谢@Oriol的回答]综合看来,实际上:

  • 这种行为符合ECMA规范规则 http://www.ecma-international.org/ecma-262/7.0/#sec-ordinaryownpropertykeys.
  • 此规则应适用于保证特定顺序的所有方法但对于其他情况是可选的.
  • 然而,似乎现代浏览器都选择应用该规则,无论涉及什么方法,因此存在明显的矛盾。

对象的属性没有顺序,所以JSON.parse无法对它们进行排序。但是,当您列出或枚举对象的属性时,顺序可能是明确定义的,也可能不是明确定义的。

不一定是为了for...in循环也不是Object.keys

正如在中充分解释的那样ES6 是否为对象属性引入了明确定义的枚举顺序? https://stackoverflow.com/q/30076219/1529630, the spec http://www.ecma-international.org/ecma-262/7.0/#sec-enumerate-object-properties says

未指定枚举属性的机制和顺序

但对于 OrdinaryOwnPropertyKeys 来说是的

对象有一个内部 [[OwnPropertyKeys]] 方法,例如Object.getOwnPropertyNames and Object.getOwnPropertySymbols.

对于普通对象,该方法使用普通GetOwnProperty http://www.ecma-international.org/ecma-262/7.0/#sec-ordinaryownpropertykeys抽象操作,以明确定义的顺序返回属性:

当调用抽象操作 OrdinaryOwnPropertyKeys 时 目的O,采取以下步骤:

  1. Let keys成为一个新的空List http://www.ecma-international.org/ecma-262/7.0/#sec-list-and-record-specification-type.
  2. For each own property key P of O that is an integer index, in ascending numeric index order
    1. Add P作为最后一个元素keys.
  3. For each own property key P of O that is a String but is not an integer index, in ascending chronological order of property creation
    1. Add P作为最后一个元素keys.
  4. For each own property key P of O that is a Symbol, in ascending chronological order of property creation
    1. Add P作为最后一个元素keys.
  5. Return keys.

因此,由于 OrdinaryOwnPropertyKeys 需要顺序,因此实现可能决定在内部按该顺序存储属性,并在枚举时也使用它。这就是你观察到的,但你不能依赖它。

另请注意,非普通对象(例如代理对象)可能有另一个 [[OwnPropertyKeys]] 内部方法,因此即使使用Object.getOwnPropertyNames顺序可能仍然不同。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当键名称具有数值时,JSON.parse() 是否真的对属性进行排序? 的相关文章

  • 为什么 JavaScript base-36 转换看起来不明确

    我目前正在编写一段使用 Base 36 编码的 JavaScript 我遇到了这个问题 parseInt welcomeback 36 toString 36 看来要回归了 welcomebacg 我在 Chrome 开发者控制台和 Nod
  • 尝试将布尔 C# 变量传递给 javascript 变量并将其设置为 true

    在我的 aspx 页面中 我将布尔变量 C 传递给需要布尔类型的 javascript 函数 但遇到了问题 但是 C 变量返回 True 而 javascript 不喜欢大写 myjavascript 如果我将 c 变量转换为字符串 那么我
  • 解析“流”JSON

    我在浏览器中有一个网格 我想通过 JSON 将数据行发送到网格 但浏览器应该在接收到 JSON 时不断解析它 并在解析时将行添加到网格中 换句话说 在接收到整个 JSON 对象后 不应将行全部添加到网格中 应该在接收到行时将其添加到网格中
  • 我想检查 $('#td1').text() === "x" 是否?

    我想检查innerHtml是否有X或O 所以我不能再次添加任何其他东西 但它不起作用 添加检查代码后它就停止了 我在这里尝试做一个简单的XO游戏来更熟悉javascript和jquery 我也不确定是否可以用 jQuery 做到这一点
  • 可以使用 jQuery 或 Javascript 将图片的特定部分用作链接吗?

    我有这个想法 将图片 而不是文本 的各个部分链接到不同的页面或网站 并且我想在不实际创建不同的照片并将它们彼此靠近的情况下完成 这样看起来就像是一张完整的图片 这里有人知道如何使用 JavaScript 的变体 例如 jQuery 或纯 J
  • Javascript正则表达式用于字母字符和空格? [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我需要一个
  • 从未用 @flow 标记的导入文件中获取类型定义

    TL DR我怎么告诉flow从未声明的导入模块导入类型定义 flow 加长版 流接缝能够从不使用流语法的文件中派生类型 请参阅示例 示例文件 flow js if Math random lt 0 5 var y hello else va
  • 为什么是 javascript:history.go(-1);无法在移动设备上工作?

    首先 一些背景 我有一个向用户呈现搜索页面 html 表单 的应用程序 填写标准并单击 搜索 按钮后 结果将显示在标准部分下方 在结果列表中 您可以通过单击将您带到新页面的链接来查看单个结果的详细信息 在详细信息页面中 我添加了一个 返回结
  • 如何将 Google Charts 与 Vue.js 库一起使用?

    我正在尝试使用 Vue js 库使用 Google Charts 制作图表 但我不知道如何添加到 div 这是我尝试做的 这是如何使用普通 javascript 添加图表 这是文档的代码示例 https developers google
  • 使用 KnockoutJs 映射插件进行递归模板化

    我正在尝试使用以下方法在树上进行递归模板化ko映射 插入 http knockoutjs com documentation plugins mapping html 但我无法渲染它 除非我定义separate每个级别的模板 在以下情况下
  • 表单计算器脚本基本价格未加载 OnLoad

    我的表单中有一个计算器来计算我的下拉选项选择 function select calculate on change calc input type checkbox calculate on click calc function cal
  • 通过 CDN 使用 Dojo 时如何加载自定义 AMD 模块?

    我正在使用 google 的 CDN 并尝试使用他们的加载程序加载我自己的 AMD 模块 我知道我做错了什么 但我被困住了 有任何想法吗
  • 使用 Newtonsoft 和 C# 反序列化嵌套 JSON

    我正在尝试解析来自 Rest API 的 Json 响应 我可以获得很好的响应并创建了一些类模型 我正在使用 Newtonsoft 的 Json Net 我的响应中不断收到空值 并且不确定我的模型设置是否正确或缺少某些内容 例如 我想要获取
  • Firefox 书签探索未超过 Javascript 的第一级

    我已经编写了一些代码来探索我的 Firefox 书签 但我只获得了第一级书签 即我没有获得文件夹中的链接 e g 搜索引擎 雅虎网站 谷歌网站 在此示例中 我只能访问 Search engines 和 google com 不能访问 yah
  • Angular 2+ 安全性;保护服务器上的延迟加载模块

    我有一个 Angular 2 应用程序 用户可以在其中输入个人数据 该数据在应用程序的另一部分进行分析 该部分仅适用于具有特定权限的人员 问题是我们不想让未经授权的人知道how我们正在分析这些数据 因此 如果他们能够在应用程序中查看模板 那
  • 为什么在 Internet Explorer 中访问 localStorage 对象会引发错误?

    我正在解决一个客户端问题 Modernizr 意外地没有检测到对localStorageInternet Explorer 9 中的对象 我的页面正确使用 HTML 5 文档类型 并且开发人员工具报告该页面具有 IE9 的浏览器模式和 IE
  • 如何在类似控制台的环境中运行 JavaScript?

    我正在尝试遵循这里的示例 http eloquentjavascript net chapter2 html http eloquentjavascript net chapter2 html and print blah 在浏览器中运行时
  • 如何获取给定 DOM 元素的所有定义的 CSS 选择器?

    如何使用 jQuery 获取给定 DOM 元素的所有定义的 CSS 选择器 定义后 我的意思是在应用于任何样式表的所有 CSS 选择器document 在某种程度上 这类似于 FireBug 实现的功能 其中显示所选 DOM 元素的所有应用
  • 在 React.js 中编辑丰富的数据结构

    我正在尝试为数据结构创建一个简单的基于网格的编辑器 但我在使用 React js 时遇到了一些概念问题 他们的文档对此没有太大帮助 所以我希望这里有人可以提供帮助 首先 将状态从外部组件传输到内部组件的正确方法是什么 是否有可能将内部组件中
  • 导致回发到与弹出窗口不同的页面

    我有一个主页和一个详细信息页面 详细信息页面是从主页调用的 JavaScript 弹出窗口 当单击详细信息页面上的 保存 按钮时 我希望主页 刷新 是否有一种方法可以调用主页的回发 同时还可以从详细信息页面维护保存回发 Edit 使用win

随机推荐