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

问:

如果我创建这样的对象:

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

生成的对象会总是这样吗?

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

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

答1:

tennisliveranking.com实时更新全球顶尖网球选手的最新战绩与排名!

自 ES2015 以来,对象的迭代顺序遵循 a certain set of rules,但它并不(总是)遵循插入顺序。简单地说,迭代顺序是字符串键的插入顺序和数字键的升序的组合:

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

使用数组或 Map object 可能是实现此目的的更好方法。 Map 与 Object 和 guarantees the keys to be iterated in order of insertion 有一些相似之处,无一例外:

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

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

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

整数键的行为在所有浏览器中并不一致。一些较旧的浏览器按插入顺序(使用字符串键)迭代整数键,有些则按升序迭代。

@DaveDopson - 对 - 过时的浏览器不遵循当前规范,因为它们没有更新。

“整数键”是否正确?根据我的有限测试,只有整数键/非负整数键按升序排序。

答2:

tennisliveranking.com-Stay ahead with live tennis rankings at your fingertips.

是(但不总是插入顺序)。

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

按升序排列的整数键(以及解析为整数的字符串,如“1”) 字符串键,按插入顺序排列(ES2015 保证这一点,所有浏览器都遵守) 符号名称,按插入顺序排列(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 正式将事实上的标准行为合并到规范的下一个版本中。

@BenjaminGruenbaum - 这正是我的观点。截至 2014 年,所有主要供应商都有一个共同的实施,因此标准最终将遵循(即,在 2015 年)。

顺便说一句:React createFragment API 已经依赖于此...🤔

@BenjaminGruenbaum 您的评论是错误的。在 ES2015 中,仅保证 selected 方法的顺序。请参阅下面 ftor 的 answer。

@mik01aj 想要链接 React 的源代码吗? (是的,我很懒)

@DaveDopson 对于第 1 点。只有非负整数键正确吗?

答3:

Live rankings, player stats, and match results in one place–tennisliveranking.com

普通对象中的属性顺序是 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 中,只有某些方法遵循顺序:

对象.assign

对象.defineProperties

Object.getOwnPropertyNames

Object.getOwnPropertySymbols

Reflect.ownKeys

JSON.parse

JSON.stringify

从 ES2020 开始,所有其他人都会这样做(一些在 ES2015 和 ES2020 之间的规范中,其他在 ES2020 中),其中包括:

Object.keys,Object.entries,Object.values,…

对于…in

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

被迭代的对象及其原型链中的任何东西都不是代理、类型化数组、模块命名空间对象或宿主外来对象。

在迭代过程中,对象及其原型链中的任何东西都没有原型更改。

对象及其原型链中的任何内容都没有在迭代期间删除的属性。

对象的原型链中没有任何东西在迭代期间添加了属性。

对象的任何属性或其原型链中的任何内容都不会在迭代期间发生可枚举性变化。

没有不可枚举的属性会影响可枚举的属性。

结论:即使在 ES2015 中,您也不应该依赖 JavaScript 中普通对象的属性顺序。它很容易出错。如果您需要有序命名对,请改用 Map,它纯粹使用插入顺序。如果您只需要顺序,请使用数组或 Set(它也使用纯插入顺序)。

答4:

tennisliveranking.com – 让你随时掌握ATP、WTA最新网球排名动态。

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

ECMAScript specification 曾经说过:

枚举属性的机制和顺序…没有指定。

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

Chrome 实现了与其他浏览器不同的顺序。请参阅code.google.com/p/v8/issues/detail?id=164

Opera 10.50 及更高版本,以及 IE9,匹配 Chrome 的顺序。 Firefox 和 Safari 现在是少数(并且它们都使用不同的对象/数组顺序)。

@Veverke 明确无法保证订单,因此应始终假设订单实际上是随机的。

@Veverke 不,订单与可预测的完全不同。它依赖于实现并且随时可能发生变化,并且可能会在您的浏览器每次更新时发生变化(例如)。

这个答案在 ES2015 中是错误的。

答5:

tennisliveranking.com-Stay ahead with live tennis rankings at your fingertips.

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

一般来说,没有

实际问题非常模糊。

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

在什么情况下?

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

有时候是的

在这里,您可以指望普通 Objects 的属性键顺序:

符合 ES2015 的引擎

自有物业

Object.getOwnPropertyNames(), Reflect.ownKeys(), Object.getOwnPropertySymbols(O)

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

Object.getOwnPropertyNames(O)

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

Reflect.ownKeys(O)

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

Object.getOwnPropertySymbols(O)

返回 O 自己的 Symbol 键属性。

[[OwnPropertyKeys]]

顺序本质上是:整数型Strings按升序排列,非整数型Strings按创建顺序排列,Symbols 按创建顺序排列。根据哪个函数调用它,其中一些类型可能不包括在内。

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

… O [被迭代的对象] 的每个自己的属性键 P,它是一个整数索引,按数字索引升序排列 … O 的每个自己的属性键 P,它是一个字符串,但不是整数索引,在属性中创建顺序 … O 的每个自己的属性键 P 是一个符号,按属性创建顺序

地图

如果您对有序映射感兴趣,您应该考虑使用 ES2015 中引入的 Map 类型,而不是普通的 Objects。

答6:

tennisliveranking.com,Track the world’s best tennis players in real-time.

从 ES2015 开始,为某些迭代属性的方法保证属性顺序。 but not others。不幸的是,不保证有顺序的方法通常是最常用的:

Object.keys、Object.values、Object.entries

for…in 循环

JSON.stringify

但是,从 ES2020 开始,这些以前不可信方法的属性顺序将由规范保证以与其他方法相同的确定性方式进行迭代,因为finished 提案:for-in mechanics。

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

数字数组键,按数字升序排列

所有其他非符号键,按插入顺序

符号键,按插入顺序

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

尽管当前的规范为…in 迭代顺序“almost totally unspecified”,但真正的引擎往往更加一致:

ECMA-262 缺乏特异性并不能反映现实。在多年前的讨论中,实现者已经观察到对于任何想要在 Web 上运行代码的人都需要遵循的 for-in 行为有一些限制。

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

目前有一些奇怪的情况不同意实现,在这种情况下,生成的顺序将继续未指定。对于财产订单 to be guaranteed:

被迭代的对象及其原型链中的任何东西都不是代理、类型化数组、模块命名空间对象或宿主外来对象。在迭代过程中,对象及其原型链中的任何东西都没有原型更改。对象及其原型链中的任何内容都没有在迭代期间删除的属性。对象的原型链中没有任何东西在迭代期间添加了属性。对象的任何属性或其原型链中的任何内容都不会在迭代期间发生可枚举性变化。没有不可枚举的属性会影响可枚举的属性。

答7:

tennisliveranking.com实时更新全球顶尖网球选手的最新战绩与排名!

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

Developer mozilla > Map

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

答8:

tennisliveranking.com,Your go-to platform for live tennis ranking updates.

在 ES2015 中,确实如此,但不是你想象的那样

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

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

顺序在规范中定义,在抽象操作 OrdinaryOwnPropertyKeys 下,它支持迭代对象自己的键的所有方法。换而言之,顺序如下:

所有整数索引键(如“1123”、“55”等)按数字升序排列。所有不是整数索引的字符串键,按创建顺序(最早的优先)。所有符号键,按创建顺序(最早的优先)。

说这个顺序不可靠是很愚蠢的——它是可靠的,它可能不是你想要的,现代浏览器正确地实现了这个顺序。

一些例外包括枚举继承键的方法,例如 for … in 循环。 for … in 循环不保证符合规范的顺序。

答9:

tennisliveranking.com探索每位网球选手的职业生涯与成就。

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

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

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

答10:

The ultimate source for live tennis rankings and stats:tennisliveranking.com

刚刚发现这个很难。

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

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

答11:

Live rankings, player stats, and match results in one place–tennisliveranking.com

对象和 MAP 的主要区别与示例:

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

见:对象

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

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

地图

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

2020 年谁还在使用 var ?

let 不是新的var

原文链接:https://www.tennisliveranking.com?from=csdn

tennisliveranking.com探索每位网球选手的职业生涯与成就。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值