JavaScript保证对象属性顺序?

如果我创build一个这样的对象:

var obj = {}; obj.prop1 = "Foo"; obj.prop2 = "Bar"; 

产生的对象是否总是像这样?

 { prop1 : "Foo", prop2 : "Bar" } 

也就是说,这些属性的排列顺序是否与我添加的顺序相同?

不,在JavaScript中不保证对象中的属性顺序; 你需要使用一个Array

从ECMAScript第三版定义对象(pdf) :

4.3.3对象

一个对象是Objecttypes的成员。 它是一个无序的属性集合,每个属性都包含一个原始值,对象或函数。 存储在对象属性中的函数称为方法。

由于ECMAScript 2015 ,使用Map对象可能是另一种select。 一个Map与一个Object有一些相似之处,并保证键的顺序 :

一个Map按照插入顺序迭代其元素,而没有为Objects指定迭代顺序。

当前语言规范 :从技术上讲,订单是未指定的。

当前浏览器 :顺序被保留,除了像“7”这样的键被parsing为整数并且由Chrome / V8以不同方式处理的主键例外。

未来的语言规范(> ES2015) :通常,您可以期望今天订购的东西不会变得无序。 新的API将保证秩序; 现有的API很难改变。 有关更多详细信息,请参阅JMM的答案。

上面最好的链接是Tim Down的评论:

http://code.google.com/p/v8/issues/detail?id=164

该漏洞详细介绍了Chrome实现密钥sorting所涉及的devise决策。 一个外卖是对于不parsing为整数(即​​“a”或“b”,但不是“3”)的string键,键在所有主stream浏览器上以插入顺序打印,并且这种行为不是“标准化”,它被浏览器厂商认为是一个重要的向后兼容性问题。 使用风险自负。

每一个(颇有见地的)评论:

标准总是遵循实现,这就是XHR来自哪里,而Google通过实现Gears来实现相同的function,然后采用相同的HTML5function。 正确的做法是让ECMA将事实上的标准行为正式纳入规范的下一版本。

如果您依赖于插入顺序,那么您不在ECMAScript规范中, 只要您的键不作为整数进行分析即可

在撰写本文时,大多数浏览器确实按照插入的顺序返回属性,但显然不能保证行为,所以不应该依赖它。

ECMAScript规范曾经说:

没有指定枚举属性的机制和顺序。

但是,在ES2015和更高版本中,非整数键将以插入顺序返回。

正常对象的属性是Javascript中的一个复杂主题。

虽然在ES5中明确没有指定任何订单,但ES2015在某些情况下有订单。 鉴于以下目的:

 o = Object.create(null, { m: {value: function() {}, enumerable: true}, "2": {value: "2", enumerable: true}, "b": {value: "b", enumerable: true}, 0: {value: 0, enumerable: true}, [Symbol()]: {value: "sym", enumerable: true}, "1": {value: "1", enumerable: true}, "a": {value: "a", enumerable: true}, }); 

这导致以下顺序(在某些情况下):

 Object { 0: 0, 1: "1", 2: "2", b: "b", a: "a", Symbol(): "sym" } 
  1. 类似整数的键按升序排列
  2. 正常的按键在插入顺序
  3. 符号按照插入顺序

因此,有三个部分,可能会改变插入顺序(如在示例中所发生的)。 类似整数的键并不完全符合插入顺序。

问题是,在ES2015规范中保证这个顺序的是什么方法?

以下方法保证显示的顺序:

  • Object.assign
  • Object.defineProperties
  • Object.getOwnPropertyNames
  • Object.getOwnPropertySymbols
  • Reflect.ownKeys

以下方法/循环保证没有顺序:

  • Object.keys
  • 的for..in
  • JSON.parse
  • JSON.stringify

结论:即使在ES2015中,也不应该依赖Javascript中正常对象的属性顺序。 这很容易出错。 改用Map

这整个答案是在遵守规范的情况下,而不是任何引擎在特定时刻或历史上所做的。

一般来说,不

实际的问题非常模糊。

将属性的顺序,我添加它们

在什么情况下?

答案是:这取决于许多因素。 一般来说, 没有

有时候是

这里是你可以指望普通Objects属性键顺序:

  • 符合ES2015的发动机
  • 自己的属性
  • Object.getOwnPropertyNames()Reflect.ownKeys()Object.getOwnPropertySymbols(O)

在所有情况下,这些方法都包含由[[OwnPropertyKeys]]指定的非枚举属性键和顺序键(见下文)。 它们包含的键值types( String和/或Symbol )不同。 在这个上下文中, String包含整数值。

Object.getOwnPropertyNames(O)

返回O自己的String keyed属性( 属性名称 )。

Reflect.ownKeys(O)

返回O自己的StringSymbol键属性。

Object.getOwnPropertySymbols(O)

返回O自己的Symbol密钥属性。

[[OwnPropertyKeys]]

顺序基本上是:按照升序排列的整数类Strings在创build顺序中非整数类Strings在创build顺序中符号。 根据哪个函数调用这个函数,可能不包括这些types中的一些。

具体语言是按以下顺序返回键:

  1. …每个自己的O [被迭代的对象]的属性关键字P是一个整数索引,按照递增的数字索引顺序

  2. …属性创build顺序中的每个属性O的属性键P ,它是一个string,但不是一个整数索引

  3. …属性创build顺序中的每个属性O的属性关键字P

Map

如果您对有序地图感兴趣,则应考虑使用ES2015中引入的Maptypes而不是普通Objects

在现代浏览器中,您可以使用地图数据结构而不是对象。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

一个Map对象可以迭代它的元素在插入顺序中…

正如其他人所说,当迭代对象的属性时,您不能保证顺序。 如果您需要多个字段的有序列表,我build议创build一个对象数组。

 var myarr = [{somfield1: 'x', somefield2: 'y'}, {somfield1: 'a', somefield2: 'b'}, {somfield1: 'i', somefield2: 'j'}]; 

这样你可以使用一个普通的循环,并有插入顺序。 如果需要的话,你可以使用Arraysorting方法将其sorting为一个新的数组。

从JSON标准 :

对象是零个或多个名称/值对的无序集合,其中名称是string,值是string,数字,布尔值,空值,对象或数组。

(强调我的)。

所以,不,你不能保证订单。