JavaScript是否保证对象属性顺序?

2020/09/22 17:01 · javascript ·  · 0评论

如果我创建这样的对象:

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

生成的对象会始终看起来像这样吗?

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

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

自ES2015起,对象的迭代顺序遵循一组特定的规则,但不(始终)遵循插入顺序简而言之,迭代顺序是字符串键的插入顺序和数字键的升序的组合:

// key order: 1, foo, bar
const obj = { "foo": "foo", "1": "1", "bar": "bar" }

使用数组或Map对象可能是实现此目的的更好方法。Map密钥共享一些相似之处Object保证密钥按插入顺序进行迭代,无一例外:

Map中的键是有序的,而添加到对象中的键则没有顺序。因此,在对其进行迭代时,Map对象将按插入顺序返回键。(请注意,在ECMAScript 2015规范中,对象确实会保留字符串和符号键的创建顺序,因此仅使用字符串键遍历对象即会按插入顺序产生键)

请注意,在ES2015之前根本无法保证对象中的属性顺序。ECMAScript第三版(pdf)中对象的定义

4.3.3对象

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

是(用于非整数键)。

大多数浏览器将对象属性迭代为:

  1. 以升序排列的整数键(以及像“ 1”这样的字符串解析为整数)
  2. 字符串键,按插入顺序排列(ES2015保证这样做,并且所有浏览器都遵守)
  3. 符号名称,按插入顺序排列(ES2015保证这样做,并且所有浏览器都遵守)

一些较旧的浏览器将类别#1和#2组合在一起,以插入顺序迭代所有键。如果您的键可能解析为整数,则最好不要依赖任何特定的迭代顺序。

保留当前语言规范(自ES2015起)的插入顺序,但键解析为整数(例如“ 7”或“ 99”)的情况除外,在这种情况下浏览器的行为会有所不同。例如,当键解析为数字时,Chrome / V8不遵守插入顺序。

旧语言规范(ES2015之前):迭代顺序在技术上未定义,但所有主流浏览器均符合ES2015行为。

请注意,ES2015行为是语言规范受现有行为驱动的一个很好的例子,而不是相反。要更深入地了解这种向后兼容的思维方式,请参阅http://code.google.com/p/v8/issues/detail?id=164,这是一个Chrome错误,其中详细介绍了Chrome迭代顺序行为背后的设计决策。在该错误报告中,每(有一些自以为是)评论:

标准始终遵循实现,这就是XHR的来历,而Google通过实现Gears然后采用等效的HTML5功能来做同样的事情。正确的解决方法是让ECMA将事实上的标准行为正式纳入规范的下一个修订版。

普通对象中的属性顺序是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",
  m: function() {},
  Symbol(): "sym"
}
  1. 类整数键升序
  2. 普通键插入顺序
  3. 插入顺序中的符号

因此,存在三个段,它们可能会更改插入顺序(如示例中所示)。而且类似整数的键根本不遵守插入顺序。

问题是,在ES2015规范中可以保证用哪种方法订购此顺序?

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

  • 对象分配
  • Object.defineProperties
  • Object.getOwnPropertyNames
  • Object.getOwnPropertySymbols
  • Reflect.ownKeys

下列方法/循环完全保证没有顺序:

  • 对象键
  • 在..in
  • JSON.parse
  • JSON.stringify

结论:即使在ES2015中,您也不应依赖Javascript中普通对象的属性顺序。容易出错。使用Map代替。

在撰写本文时,大多数浏览器的确按插入时的顺序返回属性,但明确地不能保证其行为,因此不应该依赖它。

ECMAScript规范常说的:

未指定枚举属性...的机制和顺序。

但是,在ES2015及更高版本中,非整数密钥将按插入顺序返回。

整个答案是在符合规范的情况下进行的,而不是任何引擎在特定时刻或历史上的行为。

通常没有

实际问题非常模糊。

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

在什么情况下?

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

有时候是的

在这里,您可以依靠Plain的属性键顺序Objects

  • 符合ES2015的引擎
  • 自己的财产
  • Object.getOwnPropertyNames()Reflect.ownKeys()Object.getOwnPropertySymbols(O)

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

Object.getOwnPropertyNames(O)

返回O自己的String键控属性(属性名)。

Reflect.ownKeys(O)

返回O自己的String-和Symbol-keyed属性。

Object.getOwnPropertySymbols(O)

返回O自己的Symbol键属性。

[[OwnPropertyKeys]]

顺序本质上是:Strings升序类似整数Strings,创建次序非整数,符号创建次序。根据哪个函数调用此功能,可能不包括其中某些类型。

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

  1. ...每个自己的财产键PO[对象被迭代]认为是一个整数指数,在上升的数字顺序索引

  2. ......每一个自己的财产关键PO是一个字符串,但不是整数指数,物业创建顺序

  3. ......每一个自己的财产关键PO是一个符号,在属性创建顺序

Map

如果您对有序地图感兴趣,则应考虑使用MapES2015中引入类型,而不是plain Objects

在现代浏览器中,您可以使用Map数据结构代替对象。

开发人员mozilla>地图

Map对象可以按插入顺序迭代其元素。

从ES2015开始,某些迭代属性的方法将保证属性顺序。但没有其他人不幸的是,不能保证有顺序的方法通常是最常用的:

  • Object.keysObject.valuesObject.entries
  • for..in 循环
  • JSON.stringify

但是,从ES2020开始,由于已完成的提议:for- inchanicals,规范保证以与其他方法相同的确定性方式来迭代这些以前不可信任的方法的属性顺序

就像具有保证迭代顺序的方法(如Reflect.ownKeysObject.getOwnPropertyNames)一样,先前未指定的方法也将按以下顺序进行迭代:

  • 数字数组键,按升序排列
  • 所有其他非符号键,按插入顺序
  • 符号键,按插入顺序

这几乎是每个实现都已经做过的(并且已经做了很多年),但是新的提案已将其正式化。

尽管当前规范以迭代顺序“ 几乎完全未指定,但实际引擎趋向于更加一致:”

ECMA-262中缺乏特异性并不能反映现实。在过去的讨论中,实现者观察到for-for的行为存在一些限制,任何想要在网络上运行代码的人都必须遵循。

因为每个实现都已经可以预测地遍历属性,所以可以将其放入规范中而不会破坏向后兼容性。


当前有几种奇怪的情况,实现尚无法达成共识,在这种情况下,结果顺序将继续不确定。为了保证财产顺序

被迭代的对象或其原​​型链中的任何内容都不是代理,类型化数组,模块名称空间对象或宿主外来对象。

在迭代过程中,对象或其原​​型链中的任何内容都没有原型更改。

在迭代过程中,对象及其原型链中的任何内容均未删除任何属性。

对象的原型链中没有任何内容在迭代过程中添加。

在迭代过程中,对象或其原​​型链中的任何属性都没有可枚举性更改。

没有任何不可枚举的属性会掩盖不可枚举的属性。

在ES2015中,它确实可以,但并非您可能认为的那样

直到ES2015才保证对象中键的顺序。它是实现定义的。

但是,在ES2015中指定。像JavaScript中的许多事情一样,这样做是出于兼容性目的,并且通常反映了大多数JS引擎中的现有非官方标准(您知道-谁是例外)。

该顺序在规范中的抽​​象操作OrdinaryOwnPropertyKeys下定义,该操作支持对对象自己的键进行迭代的所有方法。解释如下,顺序如下:

  1. 所有整数索引键(这样的东西"1123""55"等),在上升的数字顺序。

  2. 所有不是整数索引的字符串键(按创建顺序(最早的优先顺序))。

  3. 所有符号键,按创建顺序(最早的顺序)。

说这个命令不可靠是很愚蠢的-它是可靠的,可能不是您想要的,现代浏览器正确地实现了这个命令。

某些例外情况包括枚举继承的键的方法,例如for .. in循环。for .. in根据规范循环不保证秩序。

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

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

这样,您可以使用常规的for循环并具有插入顺序。然后,您可以根据需要使用Array sort方法将其排序到一个新数组中。

刚刚发现这很难。

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

因此,为了使用Object.keys(valueFromStore)I Object.keys(valueFromStore).sort(),我至少现在对这些键具有字母顺序。

对象和MAP之间的主要区别,例如:

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

查看:
对象

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

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

地图

    let 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"**

根据JSON标准

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

(强调我的)。

因此,不,您不能保证订单。

本文地址:http://javascript.askforanswer.com/javascriptshifoubaozhengduixiangshuxingshunxu.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!