【问题标题】:Javascript - maintain key order when going from object -> arrayJavascript-从对象->数组时保持键顺序
【发布时间】:2015-07-14 14:12:02
【问题描述】:

我知道在 JS 对象中不能保证键顺序,但是,我的数据结构来自我无法控制的后端。从以下位置出发时,我可以做些什么来保留密钥顺序:

var obj = {
   foo: 'bar',
   bar: 'foo' 
};

到:

Object.keys(obj); // hoping for ['foo', 'bar']

不幸的是,我保持密钥顺序是最重要的......

【问题讨论】:

  • 当密钥顺序本身不确定时,您希望如何维护密钥顺序? :S
  • 不幸的是,确实不能保证属性排序。顺序将是任何它发生的事情。为什么它很重要?
  • @DanPantry 该对象是从 Python 后端发送的 JSON 中解析出来的……也许确实支持键顺序?
  • Python 做什么并不重要。
  • 一旦对象越过 JSON 障碍,就无法保证您的属性的顺序(这是有道理的,因为您不能'真正'排序'属性)。将每个属性放入数组中自己的对象中并发送它可能更有意义。数组保留键顺序。即使您可以在对象转换为数组时保持对象的顺序,但对象的原始顺序无论如何都是不确定的,因此您永远无法定义对象的顺序无论如何。

标签: javascript


【解决方案1】:

没有。正如你所写:

我知道 JS 对象不保证键顺序

如果你想要你需要使用数组的顺序。如果你有一个对象,那么属性没有定义的顺序。

【讨论】:

  • 这个。唯一的例外是,如果您可以在它实际上是一个 Javascript 对象之前(即当它仍然是一个字符串时)获取后端发送的 JSON,并解析该字符串以获得它的键。当然,这绝不是理想的,但在技术上是可行的。
【解决方案2】:

JSON specification 表示

对象是零个或多个名称/值对的无序集合...

严格来说,文字 JSON 文本当然有一个顺序:文本不会突然自己打乱。但是您想要的行为——一组 有序 名称/值对——不是 JSON 提供的构造。您希望对象表示法提供超出 JSON 规范要求的语义的语义含义。

换句话说,在 JSON 中执行此操作

{
    "foo": "baz",
    "bar": "egg" 
}

是无序集的描述。如果您打算用它来描述一个有序集,那么您就没有遵循 JSON 的规则。数据恰好是有序的(因为这就是字符序列的工作方式),但 JSON 语义允许实现在考虑输入字符串中存在的数据时完全忽略名称/值对的顺序。

您可以编写直接对 JSON 输入字符串进行操作的代码,以在某处记住键的输入顺序的方式解析文本,但不需要 JSON 解析器实现来为您提供该功能。

正确的 JSON 惯用解决方案是在 JSON 响应中提供一组键名:

{
    data: {
        "foo": "baz",
        "bar": "egg" 
    },
    order: ["foo", "bar"]
}

显然,如果您不控制响应,就无法做到这一点。通过选择表示对象中的数据,响应的作者断言键的顺序纯粹是任意的。如果 JSON 的作者打算断言键条目的顺序,则该断言在 JSON 规则之外。

实际上,大多数 JavaScript 引擎通常会选择按照属性创建的顺序报告键名。但是,任何规范都不需要这种行为(有时在极端情况下不一致),因此引擎和版本之间可能在法律上有所不同。

【讨论】:

  • 我觉得这个答案如果是为观众写的,会得到更好的回应。这读起来更像是文档,而不是对它的解释。
【解决方案3】:

ECMA-262 未指定枚举顺序。事实上的标准是匹配插入顺序。

虽然对数组索引的枚举顺序(即可以解析为integer 的属性名称)没有任何保证,因为数组索引的插入顺序会产生大量内存 开销。

编辑: 添加了 jsfiddle example

var obj1 = {
   a: 'test1',
   b: 'test2' 
};

var obj2 = {
   2: 'test1',
   1: 'test2' 
};
// max 32bit unsigned is 2,147,483,647
var obj3 = {
   2147483649: 'test1',
   2147483648: 'test2' 
};
// max 64bit unsigned is 9,223,372,036,854,775,807
var obj4 = {
   9223372036854770: 'test1',
   9223372036854768: 'test2',
};

// != number < 2,147,483,647, order is not changed
console.log(Object.keys(obj1));
// < 2,147,483,647, order is changed
console.log(Object.keys(obj2));
// > 2,147,483,647, order is not changed in Firefox, but changed in Chrome
console.log(Object.keys(obj3));
// > 9,223,372,036,854,775,807, order is not changed in neither Firefox or Chrome
console.log(Object.keys(obj4));

这意味着 Chrome 的 javascript 引擎 V8 将订购任何 64bit unsigned 数字,而 Firefox 的 javascript 引擎 SpiderMonkey 将订购任何 32bit unsigned 数字。

【讨论】:

    猜你喜欢
    • 2011-08-12
    • 1970-01-01
    • 2021-01-05
    • 2018-07-07
    • 2018-06-04
    • 2017-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多