JavaScript 是否保证对象属性顺序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5525795/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Does JavaScript Guarantee Object Property Order?
提问by mellowsoon
If I create an object like this:
如果我创建一个这样的对象:
var obj = {};
obj.prop1 = "Foo";
obj.prop2 = "Bar";
Will the resulting object alwayslook like this?
生成的对象总是这样吗?
{ prop1 : "Foo", prop2 : "Bar" }
That is, will the properties be in the same order that I added them?
也就是说,属性是否与我添加它们的顺序相同?
采纳答案by bpierre
The iteration order for objects follows a certain set of rulessince ES2015, but it does not (always) follow the insertion order. Simply put, the iteration order is a combination of the insertion order for strings keys, and ascending order for number-like keys:
自 ES2015 以来,对象的迭代顺序遵循一组特定规则,但它并不(总是)遵循插入顺序。简单地说,迭代顺序是字符串键的插入顺序和数字键的升序的组合:
// key order: 1, foo, bar
const obj = { "foo": "foo", "1": "1", "bar": "bar" }
Using an array or a Map
objectcan be a better way to achieve this. Map
shares some similarities with Object
and guarantees the keys to be iterated in order of insertion, without exception:
使用数组或Map
对象可能是实现此目的的更好方法。Map
与键有一些相似之处Object
并保证按插入顺序迭代键,无一例外:
The keys in Map are ordered while keys added to object are not. Thus, when iterating over it, a Map object returns keys in order of insertion. (Note that in the ECMAScript 2015 spec objects do preserve creation order for string and Symbol keys, so traversal of an object with ie only string keys would yield keys in order of insertion)
Map 中的键是有序的,而添加到对象的键则不是。因此,当迭代它时,一个 Map 对象按插入的顺序返回键。(请注意,在 ECMAScript 2015 规范中,对象确实保留了字符串和符号键的创建顺序,因此遍历具有 ie 仅字符串键的对象将按插入顺序生成键)
As a note, properties order in objects weren't guaranteed at all before ES2015. Definition of an Object from ECMAScript Third Edition (pdf):
请注意,在 ES2015 之前,根本无法保证对象中的属性顺序。ECMAScript 第三版中的对象定义(pdf):
4.3.3 Object
An object is a member of the type Object. It is an unordered collection of propertieseach of which contains a primitive value, object, or function. A function stored in a property of an object is called a method.
4.3.3 对象
对象是对象类型的成员。它是一个无序的属性集合,每个属性都包含一个原始值、对象或函数。存储在对象属性中的函数称为方法。
回答by Dave Dopson
YES (for non-integer keys).
是(对于非整数键)。
Most Browsers iterate object properties as:
大多数浏览器将对象属性迭代为:
- Integer keys in ascending order (and strings like "1" that parse as ints)
- String keys, in insertion order (ES2015 guarantees this and all browsers comply)
- Symbol names, in insertion order (ES2015 guarantees this and all browsers comply)
- 按升序排列的整数键(以及像“1”这样解析为整数的字符串)
- 字符串键,按插入顺序(ES2015 保证这一点,所有浏览器都遵守)
- 符号名称,按插入顺序排列(ES2015 保证这一点并且所有浏览器都遵守)
Some older browsers combine categories #1 and #2, iterating all keys in insertion order. If your keys might parse as integers, it's best not to rely on any specific iteration order.
一些较旧的浏览器结合了类别 #1 和 #2,按插入顺序迭代所有键。如果您的键可能会解析为整数,最好不要依赖任何特定的迭代顺序。
Current Language Spec (since ES2015)insertion order is preserved, except in the case of keys that parse as integers (eg "7" or "99"), where behavior varies between browsers. For example, Chrome/V8 does not respect insertion order when the keys are parse as numeric.
当前语言规范(自 ES2015 起)的插入顺序被保留,但解析为整数的键(例如“7”或“99”)除外,其中的行为因浏览器而异。例如,当键被解析为数字时,Chrome/V8 不遵守插入顺序。
Old Language Spec (before ES2015): Iteration order was technically undefined, but all major browsers complied with the ES2015 behavior.
旧语言规范(ES2015 之前):迭代顺序在技术上未定义,但所有主要浏览器都遵守 ES2015 行为。
Note that the ES2015 behavior was a good example of the language spec being driven by existing behavior, and not the other way round. To get a deeper sense of that backwards-compatibility mindset, see http://code.google.com/p/v8/issues/detail?id=164, a Chrome bug that covers in detail the design decisions behind Chrome's iteration order behavior. Per one of the (rather opinionated) comments on that bug report:
请注意,ES2015 行为是语言规范由现有行为驱动的一个很好的例子,而不是相反。要更深入地了解这种向后兼容的心态,请参阅http://code.google.com/p/v8/issues/detail?id=164,这是一个 Chrome 错误,其中详细介绍了 Chrome 迭代顺序行为背后的设计决策. 根据对该错误报告的(相当固执的)评论之一:
Standards always follow implementations, that's where XHR came from, and Google does the same thing by implementing Gears and then embracing equivalent HTML5 functionality. The right fix is to have ECMA formally incorporate the de-facto standard behavior into the next rev of the spec.
标准始终遵循实现,这就是 XHR 的来源,而 Google 通过实现 Gears 然后采用等效的 HTML5 功能来做同样的事情。正确的解决方法是让 ECMA 将事实上的标准行为正式合并到规范的下一个版本中。
回答by Dave Dopson
Property order in normal Objects is a complex subject in Javascript.
普通对象中的属性顺序在 Javascript 中是一个复杂的主题。
While in ES5 explicitly no order has been specified, ES2015 has an order in certain cases. Given is the following object:
虽然在 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},
});
This results in the following order (in certain cases):
这导致以下顺序(在某些情况下):
Object {
0: 0,
1: "1",
2: "2",
b: "b",
a: "a",
m: function() {},
Symbol(): "sym"
}
- integer-like keys in ascending order
- normal keys in insertion order
- Symbols in insertion order
- 按升序排列的类似整数的键
- 按插入顺序排列的普通键
- 按插入顺序排列的符号
Thus, there are three segments, which may alter the insertion order (as happened in the example). And integer-like keys don't stick to the insertion order at all.
因此,有三个段,它们可能会改变插入顺序(如示例中发生的那样)。并且类似整数的键根本不遵守插入顺序。
The question is, for what methods this order is guaranteed in the ES2015 spec?
问题是,在 ES2015 规范中,对于哪些方法可以保证此顺序?
The following methods guarantee the order shown:
以下方法保证显示的顺序:
- Object.assign
- Object.defineProperties
- Object.getOwnPropertyNames
- Object.getOwnPropertySymbols
- Reflect.ownKeys
- 对象分配
- Object.defineProperties
- Object.getOwnPropertyNames
- Object.getOwnPropertySymbols
- 反映.ownKeys
The following methods/loops guarantee no order at all:
以下方法/循环根本不保证顺序:
- Object.keys
- for..in
- JSON.parse
- JSON.stringify
- 对象.keys
- 对于..in
- JSON.parse
- JSON.stringify
Conclusion: Even in ES2015 you shouldn't rely on the property order of normal objects in Javascript. It is prone to errors. Use Map
instead.
结论:即使在 ES2015 中,您也不应该依赖 Javascript 中普通对象的属性顺序。它很容易出错。使用Map
来代替。
回答by Alnitak
At the time of writing, most browsers did return properties in the same order as they were inserted, but it was explicitly not guaranteed behaviour so shouldn't have been relied upon.
在撰写本文时,大多数浏览器确实以与插入相同的顺序返回属性,但它明确不能保证行为,因此不应该依赖它。
The ECMAScript specificationused to say:
在ECMAScript规范常说的:
The mechanics and order of enumerating the properties ... is not specified.
枚举属性的机制和顺序......没有指定。
However in ES2015 and later non-integer keys will be returned in insertion order.
但是在 ES2015 和更高版本中,非整数键将按插入顺序返回。
回答by JMM
This whole answer is in the context of spec compliance, not what any engine does at a particular moment or historically.
这整个答案是在规范合规性的背景下,而不是任何引擎在特定时刻或历史上所做的。
Generally, no
一般来说,没有
The actual question is very vague.
实际问题非常模糊。
will the properties be in the same order that I added them
属性是否与我添加它们的顺序相同
In what context?
在什么情况下?
The answer is: it depends on a number of factors. In general, no.
答案是:这取决于许多因素。一般来说,没有。
Sometimes, yes
有时是的
Here is where you can count on property key order for plain Objects
:
在这里,您可以指望 plain 的属性键顺序Objects
:
- ES2015 compliant engine
- Own properties
Object.getOwnPropertyNames()
,Reflect.ownKeys()
,Object.getOwnPropertySymbols(O)
- 符合 ES2015 的引擎
- 自有物业
Object.getOwnPropertyNames()
,Reflect.ownKeys()
,Object.getOwnPropertySymbols(O)
In all cases these methods include non-enumerable property keys and order keys as specified by [[OwnPropertyKeys]]
(see below). They differ in the type of key values they include (String
and / or Symbol
). In this context String
includes integer values.
在所有情况下,这些方法都包括由[[OwnPropertyKeys]]
(见下文)指定的不可枚举的属性键和顺序键。它们包含的键值类型不同(String
和/或Symbol
)。在此上下文中String
包括整数值。
Object.getOwnPropertyNames(O)
Object.getOwnPropertyNames(O)
Returns O
's own String
-keyed properties (property names).
返回O
自己的String
键控属性(属性名称)。
Reflect.ownKeys(O)
Reflect.ownKeys(O)
Returns O
's own String
- and Symbol
-keyed properties.
返回O
自己的String
- 和 -Symbol
键控属性。
Object.getOwnPropertySymbols(O)
Object.getOwnPropertySymbols(O)
Returns O
's own Symbol
-keyed properties.
返回O
自己的Symbol
键控属性。
[[OwnPropertyKeys]]
[[OwnPropertyKeys]]
The order is essentially: integer-like Strings
in ascending order, non-integer-like Strings
in creation order, Symbols in creation order. Depending which function invokes this, some of these types may not be included.
顺序本质上是:Strings
升序为整数Strings
,创建顺序为非整数,创建顺序为符号。根据哪个函数调用它,其中一些类型可能不包括在内。
The specific language is that keys are returned in the following order:
具体语言是key按以下顺序返回:
... each own property key
P
ofO
[the object being iterated] that is an integer index, in ascending numeric index order... each own property key
P
ofO
that is a String but is not an integer index, in property creation order... each own property key
P
ofO
that is a Symbol, in property creation order
... [正在迭代的对象] 的每个自己的属性键
P
,O
它是一个整数索引,按数字索引升序排列......每一个自己的财产关键
P
的O
是一个字符串,但不是整数指数,物业创建顺序......每一个自己的财产关键
P
的O
是一个符号,在属性创建顺序
Map
Map
If you're interested in ordered maps you should consider using the Map
type introduced in ES2015 instead of plain Objects
.
如果你对有序映射感兴趣,你应该考虑使用Map
ES2015 中引入的类型而不是普通的Objects
。
回答by Topicus
In modern browsers you can use the Map
data structure instead of a object.
在现代浏览器中,您可以使用Map
数据结构而不是对象。
A Map object can iterate its elements in insertion order...
Map 对象可以按插入顺序迭代其元素...
回答by GregRos
In ES2015, it does, but not to what you might think
在 ES2015 中,确实如此,但不是你想的那样
The order of keys in an object wasn't guaranteed until ES2015. It was implementation-defined.
直到 ES2015 才保证对象中键的顺序。它是实现定义的。
However, in ES2015 in wasspecified. Like many things in JavaScript, this was done for compatibility purposes and generally reflected an existing unofficial standard among most JS engines (with you-know-who being an exception).
然而,在ES2015在被指定。像 JavaScript 中的许多事情一样,这样做是为了兼容性目的,并且通常反映了大多数 JS 引擎中现有的非官方标准(你知道谁是例外)。
The order is defined in the spec, under the abstract operation OrdinaryOwnPropertyKeys, which underpins all methods of iterating over an object's own keys. Paraphrased, the order is as follows:
顺序在规范中定义,在抽象操作OrdinaryOwnPropertyKeys 下,它支持迭代对象自己的键的所有方法。转述,顺序如下:
All integer indexkeys (stuff like
"1123"
,"55"
, etc) in ascending numeric order.All string keys which are not integer indices, in order of creation (oldest-first).
All symbol keys, in order of creation (oldest-first).
所有整数索引键(这样的东西
"1123"
,"55"
等),在上升的数字顺序。所有不是整数索引的字符串键,按创建顺序(最旧在前)。
所有符号键,按创建顺序(最旧在前)。
It's silly to say that the order is unreliable - it is reliable, it's just probably not what you want, and modern browsers implement this order correctly.
说顺序不可靠是愚蠢的 - 它是可靠的,它可能不是你想要的,现代浏览器正确地实现了这个顺序。
Some exceptions include methods of enumerating inherited keys, such as the for .. in
loop. The for .. in
loop doesn't guarantee order according to the specification.
一些例外包括枚举继承键的方法,例如for .. in
循环。将for .. in
根据规范循环不保证秩序。
回答by CertainPerformance
As of ES2015, property order is guaranteed for certain methods that iterate over properties. but not others. Unfortunately, the methods which are not guaranteed to have an order are generally the most often used:
从 ES2015 开始,某些迭代属性的方法可以保证属性顺序。但不是其他人。不幸的是,不能保证有订单的方法通常是最常用的:
Object.keys
,Object.values
,Object.entries
for..in
loopsJSON.stringify
Object.keys
,Object.values
,Object.entries
for..in
循环JSON.stringify
But, as of ES2020, property order for these previously untrustworthy methods willbe guaranteed by the specificationto be iterated over in the same deterministic manner as the others, due to to the finishedproposal: for-in mechanics.
但是,从 ES2020 开始,由于已完成的提议:for-in 机制,规范将保证这些以前不可信方法的属性顺序以与其他方法相同的确定性方式进行迭代。
Just like with the methods which have a guaranteed iteration order (like Reflect.ownKeys
and Object.getOwnPropertyNames
), the previously-unspecified methods will also iterate in the following order:
就像具有保证迭代顺序的方法(如Reflect.ownKeys
和Object.getOwnPropertyNames
)一样,先前未指定的方法也将按以下顺序迭代:
- Numeric array keys, in ascending numeric order
- All other non-Symbol keys, in insertion order
- Symbol keys, in insertion order
- 数字数组键,按数字升序排列
- 所有其他非符号键,按插入顺序
- 符号键,按插入顺序
This is what pretty much every implementation does already (and has done for many years), but the new proposal has made it official.
这几乎是每个实现都已经完成的(并且已经完成了很多年),但新提案已使其正式化。
Although the current specification leaves for..in iteration order "almost totally unspecified, real engines tend to be more consistent:"
尽管当前的规范保留......迭代顺序“几乎完全未指定,但实际引擎往往更加一致:”
The lack of specificity in ECMA-262 does not reflect reality. In discussion going back years, implementors have observed that there are some constraints on the behavior of for-in which anyone who wants to run code on the web needs to follow.
ECMA-262 缺乏特异性并不能反映现实。在过去几年的讨论中,实现者已经观察到 for-in 的行为存在一些限制,任何想要在网络上运行代码的人都需要遵循这些限制。
Because every implementation already iterates over properties predictably, it can be put into the specification without breaking backwards compatibility.
因为每个实现都已经以可预测的方式迭代了属性,所以可以将其放入规范中而不会破坏向后兼容性。
There are a few weird cases which implementations currently do notagree on, and in such cases, the resulting order will continue be unspecified. For property order to be guaranteed:
有一些奇怪的情况,目前的实现不同意,在这种情况下,结果的顺序将继续是未指定的。要保证财产秩序:
Neither the object being iterated nor anything in its prototype chain is a proxy, typed array, module namespace object, or host exotic object.
Neither the object nor anything in its prototype chain has its prototype change during iteration.
Neither the object nor anything in its prototype chain has a property deleted during iteration.
Nothing in the object's prototype chain has a property added during iteration.
No property of the object or anything in its prototype chain has its enumerability change during iteration.
No non-enumerable property shadows an enumerable one.
被迭代的对象及其原型链中的任何东西都不是代理、类型化数组、模块命名空间对象或主机外来对象。
在迭代过程中,对象及其原型链中的任何东西都没有原型更改。
在迭代过程中,对象及其原型链中的任何内容都没有删除属性。
对象的原型链中没有任何东西在迭代期间添加属性。
在迭代过程中,对象或其原型链中的任何属性都不会改变其可枚举性。
没有不可枚举的属性会影响可枚举的属性。
回答by Drew Durham
As others have stated, you have no guarantee as to the order when you iterate over the properties of an object. If you need an ordered list of multiple fields I suggested creating an array of objects.
正如其他人所说,当您迭代对象的属性时,您无法保证顺序。如果您需要多个字段的有序列表,我建议创建一个对象数组。
var myarr = [{somfield1: 'x', somefield2: 'y'},
{somfield1: 'a', somefield2: 'b'},
{somfield1: 'i', somefield2: 'j'}];
This way you can use a regular for loop and have the insert order. You could then use the Array sort method to sort this into a new array if needed.
这样您就可以使用常规的 for 循环并具有插入顺序。然后,如果需要,您可以使用数组排序方法将其排序为一个新数组。
回答by kriskate
Just found this out the hard way.
刚刚发现这一点很困难。
Using React with Redux, the state container of which's keys I want to traverse in order to generate children is refreshed everytime the store is changed (as per Redux's immutability concepts).
将 React 与 Redux 一起使用,每次更改存储时都会刷新我想要遍历以生成子项的键的状态容器(根据 Redux 的不变性概念)。
Thus, in order to take Object.keys(valueFromStore)
I used Object.keys(valueFromStore).sort()
, so that I at least now have an alphabetical order for the keys.
因此,为了使用Object.keys(valueFromStore)
我使用的Object.keys(valueFromStore).sort()
,这样我至少现在有一个按字母顺序排列的键。