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

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

生成的对象总是这样吗?

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

也就是说,属性是否与我添加它们的顺序相同?


当前回答

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

ECMAScript规范曾经说:

列举属性的机制和顺序……未指定。

但是在ES2015及以后版本中,非整数键将按插入顺序返回。

其他回答

在JavaScript中,普通对象中的属性顺序是一个复杂的主题。

虽然在ES5中没有明确地指定顺序,但ES2015在某些情况下定义了顺序,此后规范的连续更改越来越多地定义了顺序(甚至在ES2020中定义了for-in循环的顺序)。给定的是以下对象:

const 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",
  m: function() {},
  Symbol(): "sym"
}

“拥有”(非继承)属性的顺序是:

类似正整数的键,按升序排列 按插入顺序排列的字符串键 符号插入顺序

因此,有三个段,它们可以改变插入顺序(如示例中所发生的那样)。类似正整数的键完全不遵循插入顺序。

在ES2015中,只有特定的方法遵循以下顺序:

Object.assign Object.defineProperties Object.getOwnPropertyNames Object.getOwnPropertySymbols Reflect.ownKeys JSON.parse JSON.stringify

截至ES2020,所有其他都有(一些在ES2015和ES2020之间的规格,其他在ES2020),其中包括:

对象。钥匙,对象。条目,对象。值,… 对. .

最难确定的是for-in,因为它独特地包含继承属性。这在ES2020中已经完成了(除了边缘情况)。以下列表来自链接的(现在已经完成)提案,提供了未指定顺序的边缘情况:

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中,你也不应该依赖JavaScript中普通对象的属性顺序。它很容易出错。如果需要有序的命名对,则使用Map,它只使用插入顺序。如果只需要排序,则使用数组或Set(也使用纯插入顺序)。

来自JSON标准:

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

(强调我的)。

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

Object和MAP with Example的主要区别:

它是循环中的迭代顺序,在Map中它遵循创建时设置的顺序,而在OBJECT中没有。

看到的: 对象

const obj = {};
obj.prop1 = "Foo";
obj.prop2 = "Bar";
obj['1'] = "day";
console.log(obj)

**OUTPUT: {1: "day", prop1: "Foo", prop2: "Bar"}**

MAP

    const myMap = new Map()
    // setting the values
    myMap.set("foo", "value associated with 'a string'")
    myMap.set("Bar", 'value associated with keyObj')
    myMap.set("1", 'value associated with keyFunc')

OUTPUT:
**1.    ▶0: Array[2]
1.   0: "foo"
2.   1: "value associated with 'a string'"
2.  ▶1: Array[2]
1.   0: "Bar"
2.   1: "value associated with keyObj"
3.  ▶2: Array[2]
1.   0: "1"
2.   1: "value associated with keyFunc"**

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

一般来说,没有

实际的问题非常模糊。

属性是否与我添加它们的顺序相同

在什么情况下?

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

有时,是的

在这里你可以指望属性键顺序为普通对象:

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类型,而不是普通的对象。

这是我吃了不少苦头才知道的。

使用React和Redux,我想遍历的键的状态容器,以生成子,每次存储被更改时都会刷新(根据Redux的不变性概念)。

因此,为了获取Object.keys(valueFromStore),我使用了Object.keys(valueFromStore).sort(),这样我至少现在有了键的字母顺序。