如果我创建一个这样的对象:
var obj = {};
obj.prop1 = "Foo";
obj.prop2 = "Bar";
生成的对象总是这样吗?
{ prop1 : "Foo", prop2 : "Bar" }
也就是说,属性是否与我添加它们的顺序相同?
如果我创建一个这样的对象:
var obj = {};
obj.prop1 = "Foo";
obj.prop2 = "Bar";
生成的对象总是这样吗?
{ prop1 : "Foo", prop2 : "Bar" }
也就是说,属性是否与我添加它们的顺序相同?
当前回答
来自JSON标准:
对象是零个或多个名称/值对的无序集合,其中名称为字符串,值为字符串、数字、布尔值、空值、对象或数组。
(强调我的)。
所以,不,你不能保证订单。
其他回答
自ES2015以来,对象的迭代顺序遵循一定的规则集,但它并不(总是)遵循插入顺序。简单地说,迭代顺序是字符串键的插入顺序和数字键的升序的组合:
// key order: 1, foo, bar
const obj = { "foo": "foo", "1": "1", "bar": "bar" }
使用数组或Map对象可能是实现这一点的更好方法。Map与Object有一些相似之处,并保证键按照插入的顺序迭代,无一例外:
Map中的键是有序的,而添加到对象中的键不是有序的。因此,当对其进行迭代时,Map对象将按插入顺序返回键。(请注意,在ECMAScript 2015规范中,对象确实保留了字符串和符号键的创建顺序,因此只使用ie字符串键遍历对象会产生插入顺序的键)
值得注意的是,在ES2015之前,对象中的属性顺序根本没有得到保证。ECMAScript第三版对象定义(pdf):
4.3.3对象 对象的成员 类型的对象。它是每个属性的无序集合 包含原语值、对象或 函数。函数中存储的函数 对象的属性称为 方法。
正如其他人所述,当迭代对象的属性时,您无法保证顺序。如果你需要多个字段的有序列表,我建议创建一个对象数组。
var myarr = [{somfield1: 'x', somefield2: 'y'},
{somfield1: 'a', somefield2: 'b'},
{somfield1: 'i', somefield2: 'j'}];
这样你就可以使用一个常规的for循环,并有插入顺序。然后,如果需要,可以使用Array sort方法将其排序到一个新数组中。
这是我吃了不少苦头才知道的。
使用React和Redux,我想遍历的键的状态容器,以生成子,每次存储被更改时都会刷新(根据Redux的不变性概念)。
因此,为了获取Object.keys(valueFromStore),我使用了Object.keys(valueFromStore).sort(),这样我至少现在有了键的字母顺序。
从ES2015开始,对于迭代属性的某些方法,属性顺序得到了保证。但其他人不是。不幸的是,不保证有顺序的方法通常是最常用的:
对象。钥匙,对象。值,Object.entries 在循环. . JSON.stringify
但是,从ES2020开始,这些以前不值得信任的方法的属性顺序将由规范保证,以与其他方法相同的确定性方式迭代,这是由于完成的提议:for-in机制。
就像有保证迭代顺序的方法一样(比如Reflect。ownKeys和Object.getOwnPropertyNames),之前未指定的方法也将按以下顺序迭代:
数值数组键,按升序排列 所有其他非符号键,按插入顺序 符号键,按插入顺序
这是几乎每个实现都已经在做的事情(并且已经做了很多年),但是新提案将其正式化。
虽然目前的规范在迭代顺序中留下了..,但“几乎完全不确定,真正的引擎往往更一致:”
ECMA-262缺乏特异性并不能反映现实。在几年前的讨论中,实现者已经注意到for-in的行为有一些约束,任何想要在web上运行代码的人都需要遵循这些约束。
因为每个实现都已可预测地遍历属性,所以可以在不破坏向后兼容性的情况下将其放入规范中。
有一些奇怪的情况,实现目前没有达成一致,在这种情况下,结果的顺序将继续未指定。财产顺序担保:
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.
整个答案是在规范遵从的背景下,而不是任何引擎在特定时刻或历史上所做的。
一般来说,没有
实际的问题非常模糊。
属性是否与我添加它们的顺序相同
在什么情况下?
答案是:这取决于许多因素。一般来说,没有。
有时,是的
在这里你可以指望属性键顺序为普通对象:
ES2015兼容引擎 自己的属性 Object.getOwnPropertyNames(), Reflect.ownKeys(), Object.getOwnPropertySymbols(O)
在所有情况下,这些方法都包括不可枚举的属性键和由[[OwnPropertyKeys]]指定的顺序键(见下文)。它们所包含的键值类型不同(字符串和/或符号)。在这个上下文中,String包含整数值。
Object.getOwnPropertyNames (O)
返回O自己的string键属性(属性名)。
Reflect.ownKeys (O)
返回O自己的字符串和符号键属性。
Object.getOwnPropertySymbols (O)
返回O自己的符号键属性。
[OwnPropertyKeys]
顺序基本上是:类整数的字符串按升序排列,非类整数的字符串按创建顺序排列,符号按创建顺序排列。根据调用该函数的函数,其中一些类型可能不包括在内。
具体的语言是键按以下顺序返回:
... 每个属性键P of O[被迭代的对象]是一个整数索引,按升序数字索引 ... 每个属性键P (O)都是一个字符串,但不是一个整数索引,按属性创建顺序 ... 每个人都拥有属性键P (O),这是一个符号,按属性创建顺序
Map
如果你对有序映射感兴趣,你应该考虑使用ES2015中引入的Map类型,而不是普通的对象。