【问题标题】:Object.keys() ordering standard? [duplicate]Object.keys() 排序标准? [复制]
【发布时间】:2020-02-16 23:10:14
【问题描述】:

Object.keys()的官方订购标准是什么?
这不是关于排序的问题。这是一个超出标准的问题。

Kaushal Regmi 写道:

首先,键是按数字升序排列的整数索引。 然后,所有其他字符串键,按照它们添加到对象的顺序。 最后,所有符号键,按照它们添加到对象的顺序。 https://stackoverflow.com/a/57929312/10617101

到目前为止一切顺利。有一个仅整数作为键的对象,将在Object.keys() 返回的数组中按数字升序保存。键是否只有字母,Object.keys() 返回的数组与被调用的object{} 具有相同的顺序。我的问题是:这是 JavaScript 的通用和全球标准吗?关于这个的问题是:它安全吗?

接下来,有一个小问题。 (我不使用它)。

var object = { 3a: 'z', 1a: 'x', 2a: 'y' };
for (var i = 0; i < Object.keys(object).length; i++) {
console.log(Object.keys(object)[i]);
}
// Firefox: SyntaxError: identifier starts immediately after numeric literal
// Chrome: Uncaught SyntaxError: Invalid or unexpected token
var object = { a3: 'z', a1: 'x', a2: 'y' };
for (var i = 0; i < Object.keys(object).length; i++) {
console.log(Object.keys(object)[i]);
}
// works on both: [a3, a1, a2]

是的,解决办法是,用另一种方法创建object{}

var object = {};
object["3a"] = 'z';
object["1a"] = 'x';
object["2a"] = 'y';
for (var i = 0; i < Object.keys(object).length; i++) {
console.log(Object.keys(object)[i]);
}
// [3a, 1a, 2a]

编辑:特殊问题是对象键作为引号中的整数:

var object = { "3": "z", "1": "x", "2": "y" };
for (var i = 0; i < Object.keys(object).length; i++) {
console.log(Object.keys(object)[i]);
} // [1, 2, 3]

通常“1”是一个字符串,1 是一个整数,但作为对象键“1”仍然是一个整数。 (但不是真正通过对象键进行数学运算)。
顺便说一句,我的问题是,订单中的官方标准是什么。以及这有多安全。

【问题讨论】:

  • 是的,订单按规定指定。该语法错误与您的问题有什么关系? { "3a": ... } ...
  • Jonas Wilms:通常“1”是一个字符串,1 是一个整数,但作为对象键“1”仍然是一个整数。 (但不是真正通过对象键的数学运算)。
  • 目前还不清楚您的问题是关于对象文字的语法还是关于属性的顺序。或者问题真的是“哪些属性名称在键的排序中被视为整数?”?
  • Bergi:问题写在主题标题中。剩下的就是信息。订购是个问题。
  • 在这种情况下,它似乎与我们关于该主题的规范问题重复,您可以在其中找到标准的引用和链接。

标签: javascript javascript-objects


【解决方案1】:

spec for Object.keys() 在很大程度上是规范内部操作EnumerableOwnPropertyNames 的封装。这反过来又表明

对属性的元素进行排序,使其与使用 O 调用 EnumerateObjectProperties 内部方法时返回的迭代器生成的相对顺序相同。

EnumerateObjectProperties 然后说

没有指定枚举属性的机制和顺序,但必须符合下面指定的规则。

从“下面”来看,以下内容与您的问题相关:

  • 返回的属性键不包括符号键。
  • 在任何枚举中最多返回一次属性名称 [...]。

因此,根据规范,Object.keys() 根本没有真正的订购保证。只是一些非常基本的不变量。

这同样适用于在 EnumerateObjectProperties 中触底的语言的其他部分,特别是 for-in


将此与Reflect.ownKeys() 进行对比,至少对于ordinary objects,它在OrdinaryOwnPropertyKeys 中触底。在那里,顺序是

  • O的每个自己的属性键P是一个数组索引,按数字索引升序,做
  • O 的每个自己的属性键 P 是字符串但不是数组索引,按属性创建的时间升序排列
  • O 的每个自己的属性键 P 是一个符号,按属性创建的时间升序排列

即对于该方法,有一个明确指定的顺序。 (同样适用于其他在 OrdinaryOwnPropertyKeys 中触底的方法,例如Object.getOwnPropertyDescriptors()


有一个currently active proposal 试图对 EnumerateObjectProperties 顺序指定更强的限制,因此对for-in 也有限制。它的方法是找到涉及受限原型链和枚举的场景,其中没有任何奇怪的事情发生,并为原型链中的每个级别选择与Reflect.ownKeys() 相同的顺序。我对该提案的解读是,特别适用于Object.keys(),它将使其在普通对象上的行为与Reflect.ownKeys() 相同。 I've opened an issue on the proposal 看看我是否正确,如果正确,请更明确。

【讨论】:

  • 通常“1”是一个字符串,1是一个整数,但作为对象键“1”仍然是一个整数。 (但不是真正通过对象键的数学运算)。
  • 非常感谢 Domenic。我认为正确的答案在 9.1.11.1 OrdinaryOwnPropertyKeys 第 3 点:“是字符串但不是数组索引”。问题是,对象中的键总是整数,因为迭代器可以枚举。字符串与否无关紧要。关于这个的问题是,为什么只有整数? [a-zA-Z] 也是可枚举的(字符 Unicode 数字或位),但不是在 JS 中?对象将所有带有整数的键作为整数处理,包括字符串。那是另一个问题:var object = {1:"a","1":"b"}; Object.keys(object); // ["1"]
  • "包括字符串":包括字符串中的整数。 PS:array.sort() 也(真的)用字母对字符串进行排序。
  • 我认为这个答案不正确。 Object.keys 生成的顺序不是由 EnumerateObjectProperties 定义的,而是由 EnumerableOwnPropertyNames 定义的,因此从 ES2017 开始,Object.keys 的顺序与 Reflect.ownKeys 一样指定。
【解决方案2】:

如果对象键只有数字,javascript 将按升序排列,如果不按添加顺序排列。

var obj1 = {'3': 1, '2': 3, '1': 2};
var obj2 = {'3a': 1, '2a': 3, '1a': 2};

console.log(JSON.stringify(obj1));
Object.keys(obj1).forEach(function(key) { console.log(key); });

console.log(JSON.stringify(obj2));
Object.keys(obj2).forEach(function(key) { console.log(key); });

如果要定义以数字开头后跟字母的键,则必须用引号括起来。例如:{ '3a': 3 ,...}。

【讨论】:

  • 其实var obj1 = {3: 1, 2: 3, 1: 2}; 也可以。仅当您将数字与字母混合时。
  • 如果是整数,用引号括起来是个好主意,但它会在任何地方作为整数处理,而不是作为字符串处理。我已经在上面扩展了我的问题。
  • 通常“1”是字符串,1 是整数,但作为对象键“1”仍然是整数。 (但不是真正通过对象键的数学运算)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-11
  • 2018-08-06
  • 1970-01-01
相关资源
最近更新 更多