对象 属性 在 javascript 中排序

Object property ordering in javascript

我试图了解 javascript 对象在将它们用作关联数组时有什么用。

来自 ECMA:

4.3.3 An object is a member of the type Object. It is an unordered collection of properties each of which contains a primitive value, object, or function. A function stored in a property of an object is called a method.

在浏览器中使用它们 (chrome):

x = { 2: 'a', 3: 'b', 1: 'c' }
> Object {1: "c", 2: "a", 3: "b"}

y = { 'b': 2, 'c': 3, 'a': 1 }
> Object {b: 2, c: 3, a: 1}

虽然在第一个以数字作为键的示例中,它们是有序的,但在第二个以字符串为键的示例中,它们不会(有序 = a,b,c)。

我将这些对象与字符串键一起使用,我真的不希望它们在应用程序的某个阶段更改顺序(如果可能的话),因为它可能会使我正在使用的管道崩溃。

问题是,这种方法对每台 javascript 机器来说是否安全且正常,还是我应该使用其他方法来保证订单永远不会改变?

谢谢!

编辑: 我将它与 node.js 一起使用,它在 V8(chrome 引擎)上运行,'orders non-numerical properties in insertion order'(Felix Kling)。 V8 的这种行为可能会改变吗?

虽然 Chrome 在对象中使用数字作为索引时可以保证 属性 顺序,但 ECMA 规范并没有说 应该 这样做,所以保证我不会依赖这种行为。当您想要保持数据顺序时,我建议您重组数据以使用数组。

我从规范中读到:数组是有序的,对象不是。 Chrome 数字和数字串之间似乎没有区别。 (出于性能原因?)我有时会在需要时避开额外的键数组。

归根结底,是因为V8在代码中处处使用if/else来判断是数组索引还是对象属性而不是两个单独的类来像其他 JS 引擎一样分别处理数组和对象:

https://lastzero.net/2009/09/object-property-ordering-in-google-chrome/

是的,Google 坚持规范,但它也使得将现有数据结构从其他编程语言传递到 JS 变得困难,因为顺序变化出乎意料(甚至 John Resig 都感到惊讶!)。所以你必须使用不同的(可能更慢的)数据结构或使用转换器,这使得代码更复杂。

这取决于代码 运行 所在的环境,以及用于迭代键的方法。

在 ES5 及更早版本中,无论使用何种方法,都没有定义顺序。

在 ES6+ 中, 遍历键(但不是全部)保证按顺序遍历:

(1)递增数字键(如012),后面是

(2) 非数字键按插入顺序,后跟

(3) 个符号按插入顺序排列。

保证以这种方式运行的方法包括:

这些都是调用内部方法[[OwnPropertyKeys]],保证顺序

保证以任何顺序迭代的方法,即使在 ES6+ 环境中,包括:

  • for..in
  • Object.keysObject.valuesObject.entries
  • JSON.stringify

这些方法都调用了EnumerateObjectProperties,其中明确指出:

The mechanics and order of enumerating the properties is not specified

综上所述,尽管不能保证顺序,但在较新的环境中,上述方法几乎总是以与 Reflect.ownKeys 相同的确定顺序迭代。也许你不应该依赖它,但它可能会起作用,至少现在是这样。

如果你想要一个

method to guarantee that order won't ever change?

然后要可靠地迭代一个对象,您应该使用 Reflect.ownKeysObject.getOwnPropertyNames.

进行迭代

May this behaviour of V8 change?

如果您使用保证以特定顺序迭代的方法之一,行为将不会改变,因为 Javascript 几乎始终保持向后兼容性,现在所需的顺序已在规范,未来的任何更改都不会更改该顺序。