JavaScript 中的对象属性排序

Object property ordering in javascript

本文关键字:属性 排序 对象 JavaScript      更新时间:2023-09-26

我试图理解javascript对象有什么问题,同时将它们用作关联数组。

来自ECMA:

4.3.3 对象是对象类型的成员。它是属性的无序集合,每个属性都包含一个基元 值、对象或函数。存储在 对象称为方法。

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

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 node在V8(chrome引擎)上运行,它"按插入顺序对非数字属性进行排序"(Felix Kling)。V8 的这种行为会改变吗?

尽管 Chrome 在对象中使用数字作为索引时可以保证属性顺序,但 ECMA 规范并没有说它应该这样做,因此通过保证,我不会依赖这种行为。我建议您在要保持数据顺序时重新构建数据以使用数组。

归根结底,这是因为 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) 按插入顺序排列的符号。

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

  • Reflect.ownKeys
  • Object.getOwnPropertyNames
  • Object.getOwnPropertySymbols
  • Object.defineProperties
  • 物体休息/展开

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

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

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

这些方法都调用 EnumerateObjectProperties,它显式声明:

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

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

如果你想要一个

保证订单永远不会改变的方法?

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

V8 的这种行为会改变吗?

如果您使用保证按特定顺序迭代的方法之一,则行为不会改变,因为 Javascript 几乎总是保留向后兼容性,现在规范中已经描述了所需的顺序,将来的任何更改都不会更改该顺序。

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