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" }
- 类似整数的键按升序排列
- 正常的按键在插入顺序
- 符号按照插入顺序
因此,有三个部分,可能会改变插入顺序(如在示例中所发生的)。 类似整数的键并不完全符合插入顺序。
问题是,在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
自己的String
和Symbol
键属性。
Object.getOwnPropertySymbols(O)
返回O
自己的Symbol
密钥属性。
[[OwnPropertyKeys]]
顺序基本上是:按照升序排列的整数类Strings
在创build顺序中非整数类Strings
在创build顺序中符号。 根据哪个函数调用这个函数,可能不包括这些types中的一些。
具体语言是按以下顺序返回键:
…每个自己的
O
[被迭代的对象]的属性关键字P
是一个整数索引,按照递增的数字索引顺序…属性创build顺序中的每个属性
O
的属性键P
,它是一个string,但不是一个整数索引…属性创build顺序中的每个属性
O
的属性关键字P
Map
如果您对有序地图感兴趣,则应考虑使用ES2015中引入的Map
types而不是普通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,数字,布尔值,空值,对象或数组。
(强调我的)。
所以,不,你不能保证订单。