有没有办法对 JavaScript 对象中的键进行排序/排序?

问题描述 投票:0回答:10

例如以下

var data = {
    'States': ['NSW', 'VIC'],
    'Countries': ['GBR', 'AUS'],
    'Capitals': ['SYD', 'MEL']
}
for (var item in data) {
    console.log(item);
}

打印

States
Countries
Capitals

有没有办法按字母顺序排序以便打印

Capitals
Countries
States
javascript
10个回答
171
投票

不在对象本身内:对象的属性集合是无序的。

您可以做的一件事是使用

Object.keys()
,对数组进行排序,然后迭代它。

Object.keys(data)
      .sort()
      .forEach(function(v, i) {
          console.log(v, data[v]);
       });

针对不支持 ECMAScript 第五版的浏览器的补丁(实现):


63
投票

这是一个很好的功能解决方案:

基本上,

  1. 使用
    Object.keys
  2. 将密钥提取到列表中
  3. sort
    按键
  4. 将列表缩减回对象以获得所需的结果

ES5 解决方案:

not_sorted = {b: false, a: true};

sorted = Object.keys(not_sorted)
    .sort()
    .reduce(function (acc, key) { 
        acc[key] = not_sorted[key];
        return acc;
    }, {});

console.log(sorted) //{a: true, b: false}

ES6 解决方案:

not_sorted = {b: false, a: true}

sorted = Object.keys(not_sorted)
    .sort()
    .reduce((acc, key) => ({
        ...acc, [key]: not_sorted[key]
    }), {})

console.log(sorted) //{a: true, b: false}

26
投票

你也可以这样排序。

const data = {
  States: ['NSW', 'VIC'],
  Countries: ['GBR', 'AUS'],
  Capitals: ['SYD', 'MEL']
}

const sortedObject = Object.fromEntries(Object.entries(data).sort())

我无法详细解释它为什么有效,但显然它工作得完美:)如果你不相信我,请自己尝试一下:D

请注意,您的浏览器或 Node.js 版本应支持

Object.fromEntries

有关浏览器兼容性,请检查本页底部

对于 Node,它将适用于 12 及更高版本。 对于 v1 中的 Deno。


21
投票

是的,有。 不符合 ECMAScript 标准,但跨浏览器和 Node.js 支持,而且显然很稳定。 请参阅https://stackoverflow.com/a/23202095/645715

EDIT:这将返回一个对象,其中键已排序。 您可以使用

Object.keys(...)
从对象中获取有序键。

为什么要担心对象键顺序?这种差异在某些应用程序中可能很重要,例如使用 xml2js 解析 XML,它将 XML 表示为嵌套对象,并使用 XML 标签作为哈希键。

有几个注意事项:

  • 看起来像整数的键首先出现并按数字顺序。
  • 看起来像字符串的键按插入顺序出现在接下来。
  • 此订单由
    Object.keys(obj)
  • 报道
  • for (var key in obj) {...}
    报告的顺序在 Safari、Firefox 中可能有所不同

该函数返回一个对象,其中按字母顺序插入排序键:

function orderKeys(obj) {

  var keys = Object.keys(obj).sort(function keyOrder(k1, k2) {
      if (k1 < k2) return -1;
      else if (k1 > k2) return +1;
      else return 0;
  });

  var i, after = {};
  for (i = 0; i < keys.length; i++) {
    after[keys[i]] = obj[keys[i]];
    delete obj[keys[i]];
  }

  for (i = 0; i < keys.length; i++) {
    obj[keys[i]] = after[keys[i]];
  }
  return obj;
}

这是一个快速测试:

var example = { 
      "3": "charlie",
      "p:style": "c",
      "berries": "e",
      "p:nvSpPr": "a",
      "p:txBody": "d",
      "apples": "e",
      "5": "eagle",
      "p:spPr": "b"
    }

var obj = orderKeys(example);

这回来了

{ '3': 'charlie',
  '5': 'eagle',
  apples: 'e',
  berries: 'e',
  'p:nvSpPr': 'a',
  'p:spPr': 'b',
  'p:style': 'c',
  'p:txBody': 'd' }

然后您可以获得订购的密钥:

Object.keys(obj) 

哪个回报

["3", "5", "apples", "berries", "p:nvSpPr", "p:spPr", "p:style", "p:txBody"]

6
投票

我会将此作为评论添加到 @prototype 的帖子中,但我的代表不够高。

如果有人需要

@prototype 编写的 
orderKeys 兼容 eslint-config-airbnb
 的版本:

/** * Returns and modifies the input object so that its keys are returned in sorted * order when `Object.keys(obj)` is invoked * * @param {object} obj The object to have its keys sorted * * @returns {object} The inputted object with its keys in sorted order */ const orderKeys = (obj) => { // Complying with `no-param-reassign`, and JavaScript seems to assign by reference here const newObj = obj; // Default `.sort()` chained method seems to work for me const keys = Object.keys(newObj).sort(); const after = {}; // Add keys to `after` in sorted order of `obj`'s keys keys.forEach((key) => { after[key] = newObj[key]; delete newObj[key]; }); // Add keys back to `obj` in sorted order keys.forEach((key) => { newObj[key] = after[key]; }); return newObj; };

使用

@prototype的测试:

const example = { 3: 'charlie', 'p:style': 'c', berries: 'e', 'p:nvSpPr': 'a', 'p:txBody': 'd', apples: 'e', 5: 'eagle', p:spPr: 'b' } const obj = orderKeys(example); console.log(obj); console.log(Object.keys(obj));

输出以下内容:

Babel Compiler v6.4.4 Copyright (c) 2014-2015 Sebastian McKenzie { 3: 'charlie', 5: 'eagle', apples: 'e', berries: 'e', 'p:nvSpPr': 'a', 'p:spPr': 'b', 'p:style': 'c', 'p:txBody': 'd' } [ '3', '5', 'apples', 'berries', 'p:nvSpPr', 'p:spPr', 'p:style', 'p:txBody' ]


无论它的价值如何,我在我的 React 应用程序中都需要它,以便我可以对基于

state

 对象的下拉菜单的选项进行排序,该对象是在我的 API 响应后分配的。

一开始我是这么做的

return ( // ... <Select options={Object.keys(obj).sort()} // ... /> // ... );

但意识到每次重新渲染都会调用

.sort()

 方法,因此需要 
@prototype 实现 orderKeys

https://stackoverflow.com/users/645715/prototype


3
投票
这是一个使用

lodash 对对象的键进行排序的单行代码

_.chain(obj).toPairs().sortBy(0).fromPairs().value()

使用您的示例数据:

var data = { 'States': ['NSW', 'VIC'], 'Countries': ['GBR', 'AUS'], 'Capitals': ['SYD', 'MEL'] } data = _.chain(data) .toPairs() // turn the object into an array of [key, value] pairs .sortBy(0) // sort these pairs by index [0] which is [key] .fromPairs() // convert array of pairs back into an object {key: value} .value() // return value /* { Capitals: [ 'SYD', 'MEL' ], Countries: [ 'GBR', 'AUS' ], States: [ 'NSW', 'VIC' ] } */
    

3
投票
如果您有一个更复杂的对象,其中某些属性也是对象,那么这是一个很好的解决方案。

const sortObject = (obj: any) => { const sorted = Object.keys(obj) .sort() .reduce((accumulator, key) => { if (typeof obj[key] === "object") { // recurse nested properties that are also objects if (obj[key] == null) { accumulator[key] = null; } else if (isArray(obj[key])) { accumulator[key] = obj[key].map((item: any) => { if (typeof item === "object") { return sortObject(item); } else { return item; } }); } else { accumulator[key] = sortObject(obj[key]); } } else { accumulator[key] = obj[key]; } return accumulator; }, {}); return sorted; };
    

0
投票
改进了

这个答案到ES6,缩短为一个循环并使用打字稿

function orderKeys(obj: {}) { var keys = (Object.keys(obj) as Array<keyof typeof obj>).sort((k1, k2) => { if (k1 < k2) return -1; else if (k1 > k2) return +1; else return 0; }); var helpArr = {}; for (var elem of keys) { helpArr[elem] = obj[elem]; delete obj[elem]; obj[elem] = helpArr[elem] } return obj; } var data = { 'States': ['NSW', 'VIC'], 'Countries': ['GBR', 'AUS'], 'Capitals': ['SYD', 'MEL'] }
或者使用 ES6 和 

reduce

const sorted = (Object.keys(data) as Array<keyof typeof data>).sort().reduce((r: any, k) => ({ ...r, [k]: data[k] }), {});
结果按键排序

console.log(orderKeys(data)) # similar: console.log(sorted) { Capitals: [ 'SYD', 'MEL' ], Countries: [ 'GBR', 'AUS' ], States: [ 'NSW', 'VIC' ] }
    

0
投票
这已经很旧了,但我只是想给出我认为最干净的答案。

对于那些说对象是无序的人来说,这是不正确的。

    所有大于或等于 0 的整数键 - 数字类型和字符串在解析时看起来完全相同(“4.0”与 4 的键不同,但“4”与 4 的键相同)- 都是有序的数字并放置在所有其他键之前。这是因为整数键被视为数组的索引。
  • 所有其他键均按插入顺序放置。
假设我创建了一个像这样的对象:

const obj = {}; obj.c = 'c'; obj.b = 'b'; obj[1] = 1; obj[-1] = -1; obj.a = 'a';
如果我将对象字符串化,它将看起来像:

{ "1": 1, "c": "c", "b": "b", "a": "a", "-1": -1 }
注意 

1

 是如何位于开头的,尽管它不是第一个插入的键; 
a
b
c
 按插入顺序排列在下; 
-1
 是最后一个。鉴于 -1 小于 0,它被视为字符串键,因为它不能用于索引零索引数组。它是最后插入的,因此位于最后一个位置。

就地对对象进行排序的一种非常干净的方法是按字母顺序逐一删除并重新插入属性。这将更改属性的插入顺序。

const sortObjectProperties = (obj) => { Object.entries(obj) .sort(([a], [b]) => (a < b ? -1 : 1)) .forEach(([key, value]) => { delete obj[key]; obj[key] = value; }); return obj; };
    

-3
投票
如果转换为数组不适合您的模板并且您知道对象的键,您也可以执行以下操作:

在控制器中定义一个数组,其中键的顺序正确:

this.displayOrder = [ 'firstKey', 'secondKey', 'thirdKey' ];

在模板中重复 displayOrder 的键,然后使用 ng-init 引用回您的对象。

<div ng-repeat="key in ctrl.displayOrder" ng-init="entry = ctrl.object[key]"> {{ entry.detail }} </div>
    
© www.soinside.com 2019 - 2024. All rights reserved.