109

ES6是否为对象属性引入了定义良好的枚举顺序?

var o={'1': 1,“a”:2,“b”:3}Object.keys(o);//[“1”、“a”、“b”]-此订单是否由ES6保证?for(让k输入o){控制台.log(k);}//1 2 3-此订单是否由ES6保证?
5
  • 6
  • Btw,用于对象.获取自己的属性名称,对象.获取自己的属性符号Reflect.own键订单定义。
    – 贝吉
    评论 2015年12月9日1:45
  • 10
    事实上-答案再次出现-不再是最新的:)ES2016为对象.键用于。。在里面循环和规范:19.1.2.16(Object.keys)调用7.3.21(EnumerateOwnProperties),这反过来保证:“对属性的元素进行排序,使它们的相对顺序与使用O调用Enumerate ObjectProperties内部方法时返回的Iterator生成的相对顺序相同。”-EnumerateOwnProperties反过来保证[[自己的属性键]](9.1.11)执行9.1.11.1(顺序所有属性键),以保证顺序。 评论 2017年7月17日14:43
  • 这些数字来自ES2017规范(8),可在此处免费找到:ecma国际.org/ecma-262/8.0 评论 2017年7月17日14:43
  • 6
    @本杰明·格伦鲍姆我不知道在哪里13.7.5.15枚举对象属性保证订单与[[自己的属性键]]它只说“…必须通过调用[the]内部方法获得自己的属性键[…]“。获取后如何处理它们,或者如何将它们与继承的属性合并,都留给实现。
    – 贝吉
    评论 2017年8月22日22:49

3个答案

重置为默认值
124

注:截至ES2020,甚至更老的操作,如放弃对象.键必须遵循财产顺序。这并没有改变这样一个事实,即对基本程序逻辑使用属性顺序可能不是一个好主意,因为非整数索引属性的顺序取决于属性的创建时间。


ES2015-ES2019的答案:

对于放弃,对象.键、和JSON.stringify格式:不。

对于其他一些操作:是的通常。

虽然ES6/ES2015增加了物业订单,但它不需要放弃,对象.键,或JSON.stringify格式为了遵循这个顺序,出于遗留兼容性的考虑。

放弃循环根据[[枚举]],定义为(重点矿井):

当的[[Enumerate]]内部方法O(运行)称为以下采取以下步骤:

返回Iterator对象(25.1.1.2)其下一个方法迭代的可枚举属性的所有字符串值键O(运行). The迭代器对象必须继承自%IteratorPrototype%(25.1.2).力学和秩序枚举属性的不是明确规定但必须符合以下规定的规则[1].

ES7/ES2016删除了[[Enumerate]]内部方法,而使用抽象操作枚举对象属性,但就像[[Enumerate]]一样,它没有指定任何顺序。

另请参阅以下引用对象.键:

如果实现为for-in语句,[…]

这意味着实现不需要定义特定的枚举顺序.这个已确认ECMAScript 2015语言规范项目编辑Allen Wirfs-Brock在规范完成后发表的一篇文章中写道。

其他操作,如对象.获取自己的属性名称,对象.获取自己的属性符号,对象定义属性、和Reflect.own键对于普通对象,请遵循以下顺序:

  1. 整数索引(如果适用),按升序排列。
  2. 其他字符串键(如果适用),按属性创建顺序。
  3. 符号键(如果适用),按特性创建顺序。

此行为在[[自己的属性键]]内部方法。但可以肯定的是奇异的物体对内部方法的定义略有不同。例如,代理own密钥trap可以以任何顺序返回数组:

log(Reflect.ownKeys(新代理({}{own键:()=>['3','1','2']}))); // ['3','1','2'],整数索引未排序!


[1]下面写着:

[[Enumerate]]必须获取目标对象自己的属性键犹如通过调用其[[OwnPropertyKeys]]内部方法。

并且[[OwnPropertyKeys]]的顺序是明确定义的。但不要让这混淆了你:“好像”只意味着“相同的属性”,而不是“相同的顺序”。

这可以在中看到可枚举所有者名称,它使用[[OwnPropertyKeys]]获取属性,然后对其进行排序

与迭代程序产生的相对顺序相同如果调用了[[Enumerate]]内部方法,将返回

如果需要[[Enumerate]]以与[[OwnPropertyKeys]]相同的顺序进行迭代,则无需重新排序。

15
  • 2
    我实际上找不到getOwnPropertyNames如何保证订单的信息?事实上,Firefox和Chrome的回归就是这样的Object.getOwnPropertyNames({20:'a',10:'b'})这个[ "10", "20" ]数字排序而不是书面排序。 评论 2016年4月3日21:36
  • 4
    只是好奇订单要求放弃对象.键将是一个遗留兼容性问题? 评论 2017年9月16日22:09
  • 9
    值得注意的是,虽然规范不需要放弃对象.键按照顺序,当前版本的Firefox、Chrome和Edge都需要:jsfiddle.net/arhbn3k2/1这很有道理,如果有多个枚举实现,那就很奇怪了。规范没有要求它,因为不同的引擎已经有了不同于新定义顺序的行为,委员会不想要求实现可能破坏现有代码。不过,这些实现似乎已经决定;Firefox的订单过去肯定有所不同。 评论 2017年11月3日8:40
  • @user10089632哈哈!好问题。。。答案可以就是那个旧代码应该被打破也行……至少在这方面!我认为,这可能导致异常在应该抛出的时候没有抛出,并完全改变行为。然而,我怀疑更新后的规格是否在所有情况下都像那样严格。 评论 2017年11月16日10:30
  • @52d6c6af-这是正确的2015年欧洲标准具体来说,不需要对象.键这样才能遵循新的秩序。这在ES2020中是不正确的现在需要它,尤其是因为引擎已经更新了(请参阅我2017年的评论)。由于Oriol不再为so提供帮助,我在答案的顶部添加了一个注释。 评论 2020年3月24日15:23
16

如另一个答案所述,ES2015没有定义(非常常用的)属性迭代方法的枚举顺序放弃,对象.键、和JSON.stringify格式,而它为其他方法定义枚举方法,如Reflect.own键.然而,这种不一致很快就会消失,并且全部的属性迭代方法将以可预测的方式迭代。

正如许多人在自己的JS经验和评论中所观察到的那样,尽管上述方法的规范不能保证属性迭代顺序,但每个实现几乎总是以相同的确定顺序迭代。因此,有一个(已完成的)提议,要更改规范以使此行为正式化:

指定for-in枚举顺序(第4阶段)

根据这项提议,在大多数情况下,用于。。在里面,对象.键//条目、和JSON.stringify格式保证按顺序迭代:

(1) 数字数组键

(2) 非符号键,按插入顺序

(3) 符号键,按插入顺序

其顺序与Reflect.own键以及其他已经保证以这种方式迭代的方法。

这个规范文本相当简单:枚举对象属性,调用的有问题的抽象方法用于。。在里面等,其订单习惯于待定,现在将呼叫[[自己的属性键]],这是迭代顺序的内部方法明确规定。

目前实现中存在一些奇怪的情况同意,在这种情况下,产生的命令将continue未指定,但此类案例很少。

12

这个问题是关于EcmaScript 2015(ES6)的。但需要注意的是,EcmaScript2017规范远离的之前出现在规范中的以下段落对象.键,此处引用自EcmaScript 2016规范:

如果实现为for-in语句定义了特定的枚举顺序,那么必须对步骤3中返回的数组元素使用相同的顺序。

此外,EcmaScript 2020规范删除以下段落来自可枚举OwnPropertyNames,它仍然出现在EcmaScript 2019规范中:

  1. 对的元素排序属性因此,它们的相对顺序与使用调用EnumerateObjectProperties内部方法时返回的Iterator生成的相对顺序相同O(运行).

这些删除意味着从EcmaScript 2020开始,对象.键强制执行与相同的特定顺序对象.获取自己的属性名称Reflect.own键,即中指定的常规自己的属性键。顺序为:

  1. 拥有的属性数组索引,1以升序数字索引顺序
  2. 其他自己的String属性,按属性创建的时间升序排列
  3. 自己的符号属性,按属性创建的时间升序排列

1数组索引是一个字符串值的属性键,它是规范的数字字符串2其数值是+0≤范围内的整数< 232- 1.

2A类规范数字字符串是将由ToString(目标字符串),或字符串“-0”。例如,“012”是一个规范的数字字符串,但“12”是。

应该注意的是,所有主要的实现在几年前都已经与这个订单保持一致。

2
  • 提出了一个问题,即当使用相同的操作插入属性时,它们会得到什么顺序。例如,对象文字或Object.assign()在后一种情况下,它可能是词汇的,也可能来自输入对象,但它必须这样吗? 评论 2020年3月17日17:33
  • 1
    @RobertSiemer——这在规范中得到了很好的定义:对象文本中的属性是按源代码顺序添加的(这永远是正确的)对象分配(和属性排列)遵循源对象的属性顺序。所以对象.键({a:1,b:2})(现在)是可靠的[“a”、“b”]对象.键({b:2,a:1})(现在)是可靠的[“b”、“a”]。但一般来说,最好不要依赖于对象属性的迭代顺序。依赖创建/分配的顺序很好(并且常见:const-copy={…original,x:true};可靠地创造结果副本。x个存在真的). :-) 评论 2020年3月24日15:28

你的答案

单击“发布您的答案”,表示您同意我们的服务条款并确认您已阅读我们的隐私政策.

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.