按键对JavaScript对象进行排序


532

我需要按键对JavaScript对象进行排序。

因此,以下内容:

{ 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' }

会成为:

{ 'a' : 'dsfdsfsdf', 'b' : 'asdsad', 'c' : 'masdas' }


38
早在2011年(发布此问题时),ECMAScript规范就说JavaScript对象没有固有的顺序-观察到的顺序是与实现相关的,因此无法依赖。但是,事实证明,所有JavaScript引擎都实现了或多或少相同的语义,因此现在已经在ES6中对其进行了标准化。结果,根据规范,以下许多答案曾经是正确的,但现在不正确。
Mathias Bynens


鉴于对象只是地图或根据您的语言而定的字典,您几乎没有理由这么做。顺便说一句,通常,将它们注入映射中的顺序实际上是它们在串化时所处的顺序。因此,如果您创建了新地图并基于

需要注意的是,自从Object.entriesObject.fromEntries加入JS,这可以用一个很好的短的一行实现:Object.fromEntries(Object.entries(obj).sort())
迈克Pomax“Kamermans

Answers:


471

此问题的其他答案已过时,从未与实现现实相匹配,并且由于ES6 / ES2015规范已发布而正式变得不正确。


请参见上一节物业迭代顺序探索ES6属于Axel Rauschmayer先生

所有遍历属性键的方法都以相同的顺序进行:

  1. 首先是所有数组索引,按数字排序。
  2. 然后按照创建顺序将所有字符串键(不是索引)。
  3. 然后按创建顺序排列所有符号。

所以,是的,JavaScript对象实际上是有序的,他们的键的顺序/属性是可以改变的。

以下是按字母顺序按对象的键/属性对对象进行排序的方法:

const unordered = {
  'b': 'foo',
  'c': 'bar',
  'a': 'baz'
};

console.log(JSON.stringify(unordered));
// → '{"b":"foo","c":"bar","a":"baz"}'

const ordered = {};
Object.keys(unordered).sort().forEach(function(key) {
  ordered[key] = unordered[key];
});

console.log(JSON.stringify(ordered));
// → '{"a":"baz","b":"foo","c":"bar"}'

使用var而不是const与ES5引擎兼容。


5
除了使用稍微不同的循环技术外,我真的看不到您的代码和此处的最佳答案的区别。物体是否可以说是“有序的”似乎无关紧要。这个问题的答案还是一样。已发布的规范仅在此处确认答案。
Phil

6
仅供参考,澄清了属性的枚举顺序仍然不确定:esdiscuss.org/topic/…–
Felix Kling

6
@ Phil_1984_这个答案和最高投票答案非常不同。OP的问题是如何对对象文字进行排序。投票结果最高的答案是您不能这样做,然后提供一种解决方法,将已排序的键存储在数组中,然后从已排序的数组迭代并打印键值对。该答案声称对象文字的顺序现在可以排序,并且他的示例将排序后的键值存储回对象文字,然后直接打印排序后的对象。顺便提一下,如果链接的站点仍然存在,那就太好了。
cchamberlain

6
这两个答案都仅使用Array.sort函数首先对键进行排序。OP要求对“ JavaScript对象”进行排序,并且仅使用JavaScript对象符号(JSON)来描述这两个对象。这两个对象在逻辑上是相同的,这意味着无关紧要的排序。我认为最佳答案可以更好地说明这一点。对我来说,“所有其他答案现在都正式不正确”对我来说太极端了,尤其是链接断开时。我认为问题在于“此新的ES6规范”给人一种幻觉,即Javascript对象具有键的有序列表,这简直是不正确的。
菲尔

1
请补充说,各种现代浏览器(Google“ caniuse ES6”)不支持该解决方案。使用此答案仅会冒险在某些浏览器中发现难以发现的错误(例如,在Chrome正常的情况下使用Safari)。
曼努埃尔·阿威德·施密特

244

JavaScript对象1未排序。尝试对它们进行“分类”是没有意义的。如果要遍历对象的属性,可以对键进行排序,然后检索关联的值:

var myObj = {
    'b': 'asdsadfd',
    'c': 'masdasaf',
    'a': 'dsfdsfsdf'
  },
  keys = [],
  k, i, len;

for (k in myObj) {
  if (myObj.hasOwnProperty(k)) {
    keys.push(k);
  }
}

keys.sort();

len = keys.length;

for (i = 0; i < len; i++) {
  k = keys[i];
  console.log(k + ':' + myObj[k]);
}


使用Object.keys幻想的替代实现:

var myObj = {
    'b': 'asdsadfd',
    'c': 'masdasaf',
    'a': 'dsfdsfsdf'
  },
  keys = Object.keys(myObj),
  i, len = keys.length;

keys.sort();

for (i = 0; i < len; i++) {
  k = keys[i];
  console.log(k + ':' + myObj[k]);
}


1 不必学究,但没有JSON对象之类的东西


2
@MarcelKorpel这里有一个JSON对象。检查官方JSON RFC的第8节:ietf.org/rfc/rfc4627.txt
Paul

8
@Paulpro关于RFC的两点注意事项:首先,它已经存在7年了,词汇随时间而变化;第二,“此备忘录为Internet社区提供信息。它没有指定任何类型的Internet标准。” 给定的字符序列表示JavaScript对象文字还是JSON文本取决于上下文/用法。术语“ JSON对象”充斥并以有害的方式使区分变得模棱两可。让我们摆脱不精确的术语,并尽可能使用更精确的术语。我认为没有其他理由。话语很重要。
Matt Ball

6
@MattBall IMO JSON对象是对字符串的非常精确的术语,就像{"a", 1}JSON Array是对字符串的精确术语一样[1]。拥有字符串时[{x: 1}, {y: 2}, {z: 3}],可以通过说出数组中的第三个对象之类的东西进行交流,因此很有用,因此在评论Javascript文字时,我更喜欢“这不是JSON对象”,而不是“没有这样的对象”作为JSON对象”,这将在稍后OP实际使用JSON时引起更多的混乱和通信困难。
保罗

3
@Paulpro我必须不同意。{"a", 1}是对象文字或JSON文本(如果您确实喜欢,也称为JSON字符串)。它取决于上下文,前者是否在JavaScript源代码中逐字显示,后者则是需要传递给JSON解析器以进一步使用的字符串。在允许的语法,正确的用法和序列化方面,两者之间确实存在差异。
Matt Ball

4
现在ES6 / ES2015已经完成,此答案正式变得不正确。请参阅我的答案以获取更多信息。
Mathias Bynens

171

很多人提到“对象无法排序”,但是之后他们给了您有效的解决方案。悖论,不是吗?

没有人提到为什么这些解决方案有效。之所以这样,是因为在大多数浏览器的实现中,对象中的值都是按照添加顺序存储的。这就是为什么如果您从键的排序列表中创建新对象,则会返回预期的结果。

而且我认为我们可以添加另一种解决方案– ES5功能方式:

function sortObject(obj) {
    return Object.keys(obj).sort().reduce(function (result, key) {
        result[key] = obj[key];
        return result;
    }, {});
}

ES2015以上版本(格式为“单线”):

const sortObject = o => Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})

以上示例的简短说明(如评论中所述):

Object.keys向我们提供了提供的对象(objo)中的键列表,然后我们使用默认的排序算法对它们进行排序,接下来.reduce将其用于将该数组转换回对象,但是这次所有键都已排序。


7
@Pointy此行为在所有主流浏览器中始终可用,并已在ES6 / ES2015中进行了标准化。我会说这是个好建议。
Mathias Bynens

3
这是在EcmaScript v5中完成任务的最简单,最简洁的方法。晚会晚了一点,但应该被接受。
史蒂文·德·萨拉斯

2
“之所以如此,是因为在大多数浏览器的实现中,对象中的值都是按照添加它们的顺序来存储的。”但仅适用于非数值属性。另外请注意,仍然无法保证按顺序(例如通过for...in)迭代属性。
Felix Kling

2
你们很高兴向您解释为什么它起作用了。谢谢!
奥拉

5
我的小棉人抱怨那条线(退回一项任务),但是这条线对我Object.keys(dict).sort().reduce((r, k) => Object.assign(r, { [k]: dict[k] }), {});
有用,

68

伙计们,我很震惊!当然,所有答案都有些陈旧,但是没有人甚至提到排序的稳定性!因此,请允许我尽力回答问题本身,并在此处进行详细说明。因此,我现在要道歉,这将是很多阅读的内容。

由于是2018年,所以我只会使用ES6,因此可在MDN文档中找到Polyfills,我将在给定的部分进行链接。


回答问题:

如果键只是数字,则可以安全地Object.keys()与一起使用Array.prototype.reduce()以返回已排序的对象:

// Only numbers to show it will be sorted.
const testObj = {
  '2000': 'Articel1',
  '4000': 'Articel2',
  '1000': 'Articel3',
  '3000': 'Articel4',
};

// I'll explain what reduces does after the answer.
console.log(Object.keys(testObj).reduce((accumulator, currentValue) => {
  accumulator[currentValue] = testObj[currentValue];
  return accumulator;
}, {}));

/**
 * expected output:
 * {
 * '1000': 'Articel3',
 * '2000': 'Articel1',
 * '3000': 'Articel4',
 * '4000': 'Articel2' 
 *  } 
 */

// if needed here is the one liner:
console.log(Object.keys(testObj).reduce((a, c) => (a[c] = testObj[c], a), {}));

但是,如果您使用的是字符串,我强烈建议将其链接Array.prototype.sort()到所有这些字符串中:

// String example
const testObj = {
  'a1d78eg8fdg387fg38': 'Articel1',
  'z12989dh89h31d9h39': 'Articel2',
  'f1203391dhj32189h2': 'Articel3',
  'b10939hd83f9032003': 'Articel4',
};
// Chained sort into all of this.
console.log(Object.keys(testObj).sort().reduce((accumulator, currentValue) => {
  accumulator[currentValue] = testObj[currentValue];
  return accumulator;
}, {}));

/**
 * expected output:   
 * { 
 * a1d78eg8fdg387fg38: 'Articel1',
 * b10939hd83f9032003: 'Articel4',
 * f1203391dhj32189h2: 'Articel3',
 * z12989dh89h31d9h39: 'Articel2' 
 * }
 */

// again the one liner:
console.log(Object.keys(testObj).sort().reduce((a, c) => (a[c] = testObj[c], a), {}));

如果有人想知道减少的作用是什么:

// Will return Keys of object as an array (sorted if only numbers or single strings like a,b,c).
Object.keys(testObj)

// Chaining reduce to the returned array from Object.keys().
// Array.prototype.reduce() takes one callback 
// (and another param look at the last line) and passes 4 arguments to it: 
// accumulator, currentValue, currentIndex and array
.reduce((accumulator, currentValue) => {

  // setting the accumulator (sorted new object) with the actual property from old (unsorted) object.
  accumulator[currentValue] = testObj[currentValue];

  // returning the newly sorted object for the next element in array.
  return accumulator;

  // the empty object {} ist the initial value for  Array.prototype.reduce().
}, {});

如果需要,这里是一种衬板的说明:

Object.keys(testObj).reduce(

  // Arrow function as callback parameter.
  (a, c) => 

  // parenthesis return! so we can safe the return and write only (..., a);
  (a[c] = testObj[c], a)

  // initial value for reduce.
  ,{}
);

为什么排序有点复杂:

简而言之,Object.keys()将以与正常循环相同的顺序返回数组:

const object1 = {
  a: 'somestring',
  b: 42,
  c: false
};

console.log(Object.keys(object1));
// expected output: Array ["a", "b", "c"]

Object.keys()返回一个数组,其元素是与直接在对象上发现的可枚举属性相对应的字符串。属性的顺序与手动遍历对象的属性所给出的顺序相同。

旁注-您也可以Object.keys()在数组上使用,请记住将返回索引:

// simple array
const arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']

但这并不像这些示例所示那样容易,现实世界中的对象可能包含数字,字母字符甚至符号(请不要这样做)。

这是一个所有示例都包含在一个对象中的示例:

// This is just to show what happens, please don't use symbols in keys.
const testObj = {
  '1asc': '4444',
  1000: 'a',
  b: '1231',
  '#01010101010': 'asd',
  2: 'c'
};

console.log(Object.keys(testObj));
// output: [ '2', '1000', '1asc', 'b', '#01010101010' ]

现在,如果我们Array.prototype.sort()在上面的数组上使用,输出将发生变化:

console.log(Object.keys(testObj).sort());
// output: [ '#01010101010', '1000', '1asc', '2', 'b' ]

这是来自文档的引文:

sort()方法对数组中的元素进行排序并返回该数组。排序不一定是稳定的。默认排序顺序是根据字符串Unicode代码点确定的。

排序的时间和空间复杂度无法保证,因为它取决于实现。

您必须确保其中之一为您返回了所需的输出。在现实生活中的示例中,如果您将API和数据库之类的不同信息输入一起使用,人们往往会特别混淆。


那有什么大不了的?

那么,每个程序员都应该了解两篇文章:

就地算法

在计算机科学中,就地算法是不使用辅助数据结构来转换输入的算法。但是,可以为辅助变量保留少量的额外存储空间。算法执行时,输入通常会被输出覆盖。就地算法仅通过替换或交换元素来更新输入序列。非原位算法有时称为非原位或非原位。

所以基本上我们的旧数组将被覆盖!如果您出于其他原因要保留旧阵列,则这一点很重要。因此,请记住这一点。

排序算法

稳定的排序算法按照相同元素在输入中出现的顺序对其进行排序。在对某些类型的数据进行排序时,在确定排序顺序时仅检查部分数据。例如,在右边的纸牌排序示例中,纸牌按其等级排序,而西装被忽略。这样就可以使用原始列表的多个不同的正确排序版本。稳定的排序算法会根据以下规则选择其中一种:如果两项比较相等,例如两张5张卡片,则它们的相对顺序将被保留,因此,如果输入中的一项排在另一项之前,在输出中排在另一个之前。

在此处输入图片说明

纸牌上稳定排序的示例。当纸牌按等级进行稳定排序时,两个5必须在原始输出的排序输出中保持相同的顺序。当用非稳定排序对它们进行排序时,这5个可能以相反的顺序结束排序后的输出。

这表明排序是正确的,但是它已更改。因此,在现实世界中,即使排序正确无误,我们也必须确保获得期望的结果!这也非常重要,请记住这一点。有关更多JavaScript示例,请查看Array.prototype.sort()-文档:https : //developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/sort


3
你们真是不可思议,谢谢您提供这个令人难以置信的答案。我在SO上看到的最好的之一。干杯。
加文

如果您只能提供一种怪异的方法,最后使用。很好的答案!
mmm

@momomo问题是,取决于您对排序的期望,没有正确的方法。然而,你可以简单地使用这段代码从我的回答:Object.keys(testObj).sort().reduce((a, c) => (a[c] = testObj[c], a), {})
Megajin '19

排序的稳定性是否不适用于此问题:我们正在按对象键进行排序,并且键是唯一的。(以您的卡片为例:即使包装不同,也不会有两个5s。)
Darren Cook

@DarrenCook好问题!您是对的,在一个对象中永远不会有相同的键。但是,稳定性要比密钥的唯一性更为复杂。大多数情况下,将数组包含在排序对象中。那就是一切都可能变得不稳定的时候。想象一下一个有5个玩家的纸牌游戏。每只手都由一个数组(保持单个手排序)表示,而纸牌则作为对象。如果您的卡看起来像这样,{5: 'hearts'}或者{5: 'spades'}您开始对阵列进行排序,那么在诸如拉米纸牌这样的游戏中,它可能会变得不稳定。不要说不同的语言。
Megajin

29

这对我有用

/**
 * Return an Object sorted by it's Key
 */
var sortObjectByKey = function(obj){
    var keys = [];
    var sorted_obj = {};

    for(var key in obj){
        if(obj.hasOwnProperty(key)){
            keys.push(key);
        }
    }

    // sort keys
    keys.sort();

    // create new array based on Sorted Keys
    jQuery.each(keys, function(i, key){
        sorted_obj[key] = obj[key];
    });

    return sorted_obj;
};

10
这实际上是对当前问题的正确答案。对于使用下划线的简化版本,请参见:jsfiddle.net/wPjaQ/1
开方

6
@radicand不,此答案不正确。它返回一个没有顺序的新对象。
保罗

3
@radicand实际上也没有。对象键上没有顺序,那么在实践中怎么说呢?它实际上只是为您提供了传递的对象的浅表副本
Paul

9
这是超级错误的。它可能暂时可以使用,但是会在其他Web浏览器中中断或在同一浏览器中加载不同页面。为了安全起见,浏览器可能会随机分配对象密钥,或者在您填充对象时,它将根据密钥将值放入不同的存储桶中,这将返回不同的顺序。如果这种情况发生了,那对您来说是幸运的。
Yobert

11
它还不需要使用jQuery。
RobG 2014年

25

现在是2019年,我们有一种解决这个问题的2019年方法:)

Object.fromEntries(Object.entries({b: 3, a:8, c:1}).sort())

2
我们如何按键对嵌套对象进行排序?
a2441918

@ a2441918与使用sort()函数的方式相同。看看:developer.mozilla.org/de/docs/Web/JavaScript/Reference / ... Object.fromEntries(Object.entries({b:3,a:8,c:1})。sort((k,j )=> k-j))
user2912903 '19

对于TypeScript用户,此功能尚不可用,请访问:github.com/microsoft/TypeScript/issues/30933
tsujp

不错的单行代码,但是如何以不区分大小写的方式对键进行排序?
theMaxx

1
@theMaxx使用自定义函数进行排序,例如:```Object.fromEntries(Object.entries({b:3,a:8,c:1})。sort(([[key1,val1],[key2, val2])=> key1.toLowerCase()。localeCompare(key2.toLowerCase())))`''
Ben

22

这是1班轮

var data = { zIndex:99,
             name:'sravan',
             age:25, 
             position:'architect',
             amount:'100k',
             manager:'mammu' };

console.log(Object.entries(data).sort().reduce( (o,[k,v]) => (o[k]=v,o), {} ));


这种疯狂的语法到底是什么?(o[k] = v, o)。为什么这甚至行得通,在哪里可以找到有关它的文档?它显然返回最右边的参数,但是为什么呢?
ntaso

1
@ntaso 在这里
詹姆斯

短函数首先o[k]等于等于v然后返回o
Tahsin Turkoz

19

这是一个古老的问题,但是从Mathias Bynens的答案中得到的提示,我做了一个简短的版本来对当前对象进行排序,而没有太多开销。

    Object.keys(unordered).sort().forEach(function(key) {
        var value = unordered[key];
        delete unordered[key];
        unordered[key] = value;
    });

执行代码后,“无序”对象本身将按字母顺序对键进行排序。


17

使用lodash可以正常工作:

some_map = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' }

// perform a function in order of ascending key
_(some_map).keys().sort().each(function (key) {
  var value = some_map[key];
  // do something
});

// or alternatively to build a sorted list
sorted_list = _(some_map).keys().sort().map(function (key) {
  var value = some_map[key];
  // return something that shall become an item in the sorted list
}).value();

值得深思。


15

假设它在显示无序对象属性的VisualStudio调试器中很有用。

(function(s){var t={};Object.keys(s).sort().forEach(function(k){t[k]=s[k]});return t})({b:2,a:1,c:3})

太好了,谢谢
Mugiwara

真好!谢谢您提出的这个简洁的解决方案。
Con Antonakos 2015年

9

下划线版本

function order(unordered)
{
return _.object(_.sortBy(_.pairs(unordered),function(o){return o[0]}));
}

如果您不信任浏览器保持键的顺序,我强烈建议您使用键-值对数组的有序数组。

_.sortBy(_.pairs(c),function(o){return o[0]})

更好:_.object(_.sortBy(_.pairs(unordered), _.first))
Afanasii Kurakin '19

8
function sortObjectKeys(obj){
    return Object.keys(obj).sort().reduce((acc,key)=>{
        acc[key]=obj[key];
        return acc;
    },{});
}

sortObjectKeys({
    telephone: '069911234124',
    name: 'Lola',
    access: true,
});

也许添加一些代码解释会更好。
亚里斯多德

1
获取对象的键,因此它是字符串数组,我对它们进行sort(),并且由于它是字符串(键)数组,因此我将其缩小(使用js Array的reduce())。acc最初是一个空对象{}(reducer的最后一个arg),而reducer(回调)在该空对象上分配源obj的值以及有序的键序列。
user3286817

8

也许更优雅的形式:

 /**
     * Sorts a key-value object by key, maintaining key to data correlations.
     * @param {Object} src  key-value object
     * @returns {Object}
     */
var ksort = function ( src ) {
      var keys = Object.keys( src ),
          target = {};
      keys.sort();
      keys.forEach(function ( key ) {
        target[ key ] = src[ key ];
      });
      return target;
    };


// Usage
console.log(ksort({
  a:1,
  c:3,
  b:2  
}));

PS和ES6 +语法相同:

function ksort( src ) {
  const keys = Object.keys( src );
  keys.sort();
  return keys.reduce(( target, key ) => {
        target[ key ] = src[ key ];
        return target;
  }, {});
};

没什么 您仍然返回一个对象。您无法保证目标中的对象实际上将具有任何顺序。您需要返回一个数组。ee
mmm

您在这里要做的唯一一件事就是以非最佳方式确保它是一个集合。
mmm

7

递归排序,用于嵌套对象和数组

function sortObjectKeys(obj){
    return Object.keys(obj).sort().reduce((acc,key)=>{
        if (Array.isArray(obj[key])){
            acc[key]=obj[key].map(sortObjectKeys);
        }
        if (typeof obj[key] === 'object'){
            acc[key]=sortObjectKeys(obj[key]);
        }
        else{
            acc[key]=obj[key];
        }
        return acc;
    },{});
}

// test it
sortObjectKeys({
    telephone: '069911234124',
    name: 'Lola',
    access: true,
    cars: [
        {name: 'Family', brand: 'Volvo', cc:1600},
        {
            name: 'City', brand: 'VW', cc:1200, 
            interior: {
                wheel: 'plastic',
                radio: 'blaupunkt'
            }
        },
        {
            cc:2600, name: 'Killer', brand: 'Plymouth',
            interior: {
                wheel: 'wooden',
                radio: 'earache!'
            }
        },
    ]
});

我认为您需要else在那里- Array.isArray(obj[key])typeof obj[key] === 'object'
所有人

当您具有原始数组时,您的函数会将原始数组(字符串/数字)转换为空对象。为了解决这个问题,我在您的函数开始处添加了以下内容function sortObjectKeys(obj){::if(typeof obj != 'object'){ /* it is a primitive: number/string (in an array) */ return obj; }。为了if(obj == null || obj == undefined){ return obj; }
增强

4

如前所述,对象是无序的。

然而...

您可能会发现以下成语很有用:

var o = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' };

var kv = [];

for (var k in o) {
  kv.push([k, o[k]]);
}

kv.sort()

然后,您可以遍历kv并做您想做的任何事情。

> kv.sort()
[ [ 'a', 'dsfdsfsdf' ],
  [ 'b', 'asdsad' ],
  [ 'c', 'masdas' ] ]


4

这是一个基于lodash的干净版本,可用于嵌套对象

/**
 * Sort of the keys of an object alphabetically
 */
const sortKeys = function(obj) {
  if(_.isArray(obj)) {
    return obj.map(sortKeys);
  }
  if(_.isObject(obj)) {
    return _.fromPairs(_.keys(obj).sort().map(key => [key, sortKeys(obj[key])]));
  }
  return obj;
};

如果lodash有一个toObject()方法,它甚至会更干净...


3

只需使用lodash解压缩地图,然后再次按pair和zip的第一个值进行排序,它将返回已排序的键。

如果您希望sortby值将对索引更改为1而不是0

var o = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' };
console.log(_(o).toPairs().sortBy(0).fromPairs().value())

在此处输入图片说明


请使用编辑链接来说明此代码的工作原理,而不仅仅是给出代码,因为这样的解释更有可能对未来的读者有所帮助。另请参阅“ 如何回答”来源
Jed Fox

3

在保留引用的同时递归地对键进行排序。

function sortKeys(o){
    if(o && o.constructor === Array)
        o.forEach(i=>sortKeys(i));
    else if(o && o.constructor === Object)
        Object.entries(o).sort((a,b)=>a[0]>b[0]?1:-1).forEach(e=>{
            sortKeys(e[1]);
            delete o[e[0]];
            o[e[0]] = e[1];
        });
}

例:

let x = {d:3, c:{g:20, a:[3,2,{s:200, a:100}]}, a:1};
let y = x.c;
let z = x.c.a[2];
sortKeys(x);
console.log(x); // {a: 1, c: {a: [3, 2, {a: 1, s: 2}], g: 2}, d: 3}
console.log(y); // {a: [3, 2, {a: 100, s: 200}}, g: 20}
console.log(z); // {a: 100, s: 200}

不错的摘要!delete o[e[0]];那里的目的是什么?我们不能只分配吗?
博扬

似乎只有对不存在的键的新分配将在末尾附加该键。如果删除操作被注释掉,则不会对键进行排序,至少不会在Chrome中排序。
brunettdan

这就说得通了。谢谢!在任何情况下,这都是一个失败的原因,因为根据规范js对象键没有顺序。我们只是利用obj和log函数的隐含细节
-Boyang,

是的,当键的顺序很重要时,我会使用Map:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…–
brunettdan

3
Object.keys(unordered).sort().reduce(
    (acc,curr) => ({...acc, [curr]:unordered[curr]})
    , {}
)

3

这是我进行JSON排序所需的一切的轻量级解决方案。

function sortObj(obj) {
    if (typeof obj !== "object" || obj === null)
        return obj;

    if (Array.isArray(obj))
        return obj.map((e) => sortObj(e)).sort();

    return Object.keys(obj).sort().reduce((sorted, k) => {
        sorted[k] = sortObj(obj[k]);
        return sorted;
    }, {});
}

2

如果您有嵌套的对象或嵌套的数组obj,请使用此代码。

var sortObjectByKey = function(obj){
    var keys = [];
    var sorted_obj = {};
    for(var key in obj){
        if(obj.hasOwnProperty(key)){
            keys.push(key);
        }
    }
    // sort keys
    keys.sort();

    // create new array based on Sorted Keys
    jQuery.each(keys, function(i, key){
        var val = obj[key];
        if(val instanceof Array){
            //do for loop;
            var arr = [];
            jQuery.each(val,function(){
                arr.push(sortObjectByKey(this));
            }); 
            val = arr;

        }else if(val instanceof Object){
            val = sortObjectByKey(val)
        }
        sorted_obj[key] = val;
    });
    return sorted_obj;
};

5
作者没有说自己正在使用jQuery,也没有标注jQuery。如果您在纯JavaScript中添加解决方案,那就太好了。
rusmus 2014年

感谢@Phani,这正是我所需要的
Will Sheppard

2

解:

function getSortedObject(object) {
  var sortedObject = {};

  var keys = Object.keys(object);
  keys.sort();

  for (var i = 0, size = keys.length; i < size; i++) {
    key = keys[i];
    value = object[key];
    sortedObject[key] = value;
  }

  return sortedObject;
}

// Test run
getSortedObject({d: 4, a: 1, b: 2, c: 3});

说明:

许多JavaScript运行时都按照添加顺序将值存储在对象中。

要通过对象的键对对象的属性进行排序,可以使用Object.keys函数,该函数将返回键数组。然后可以通过Array.prototype.sort()方法对键数组进行排序,该方法对数组中的元素进行适当排序(无需将它们分配给新变量)。

按键排序后,就可以开始一对一地使用它们,以访问旧对象的内容以填充新对象(现已排序)。

下面是该过程的示例(您可以在目标浏览器中对其进行测试):

/**
 * Returns a copy of an object, which is ordered by the keys of the original object.
 *
 * @param {Object} object - The original object.
 * @returns {Object} Copy of the original object sorted by keys.
 */
function getSortedObject(object) {
  // New object which will be returned with sorted keys
  var sortedObject = {};

  // Get array of keys from the old/current object
  var keys = Object.keys(object);
  // Sort keys (in place)
  keys.sort();

  // Use sorted keys to copy values from old object to the new one
  for (var i = 0, size = keys.length; i < size; i++) {
    key = keys[i];
    value = object[key];
    sortedObject[key] = value;
  }

  // Return the new object
  return sortedObject;
}

/**
 * Test run
 */
var unsortedObject = {
  d: 4,
  a: 1,
  b: 2,
  c: 3
};

var sortedObject = getSortedObject(unsortedObject);

for (var key in sortedObject) {
  var text = "Key: " + key + ", Value: " + sortedObject[key];
  var paragraph = document.createElement('p');
  paragraph.textContent = text;
  document.body.appendChild(paragraph);
}

注意: Object.keys是ECMAScript 5.1方法,但以下是旧版浏览器的polyfill:

if (!Object.keys) {
  Object.keys = function (object) {
    var key = [];
    var property = undefined;
    for (property in object) {
      if (Object.prototype.hasOwnProperty.call(object, property)) {
        key.push(property);
      }
    }
    return key;
  };
}

2

我将一些Java枚举转移到javascript对象。

这些对象为我返回了正确的数组。如果对象键是混合类型(字符串,整数,字符),则存在问题。

Types:

var TypeA = {
    "-1": "Any",
    "2": "2L",
    "100": "100L",
    "200": "200L",
    "1000": "1000L"
};

var TypeB = {
    "U": "Any",
    "W": "1L",
    "V": "2L",
    "A": "100L",
    "Z": "200L",
    "K": "1000L"
};


Sorted Keys(output):

Key list of TypeA -> ["-1", "2", "100", "200", "1000"]

Key list of TypeB -> ["U", "W", "V", "A", "Z", "K"]

2

使用lodash的简单易读的代码段。

仅在调用sortBy时,才需要将键放在引号中。它不必在数据本身中用引号引起来。

_.sortBy(myObj, "key")

另外,您要映射的第二个参数是错误的。它应该是一个函数,但是使用pluck更容易。

_.map( _.sortBy(myObj, "key") , "value");

2

@sindresorhus有一个很棒的项目叫做sort-keys,它的功能很棒。

您可以在此处查看其源代码:

https://github.com/sindresorhus/sort-keys

或者您可以将其与npm一起使用:

$ npm install --save sort-keys

这也是他的自述文件中的代码示例

const sortKeys = require('sort-keys');

sortKeys({c: 0, a: 0, b: 0});
//=> {a: 0, b: 0, c: 0}

sortKeys({b: {b: 0, a: 0}, a: 0}, {deep: true});
//=> {a: 0, b: {a: 0, b: 0}}

sortKeys({c: 0, a: 0, b: 0}, {
    compare: (a, b) => -a.localeCompare(b)
});
//=> {c: 0, b: 0, a: 0}

1

纯JavaScript答案可对对象进行排序。我知道这是唯一可以处理负数的答案。此功能用于对数字对象进行排序。

输入obj = {1000:{},-1200:{},10000:{},200:{}};

function osort(obj) {
var keys = Object.keys(obj);
var len = keys.length;
var rObj = [];
var rK = [];
var t = Object.keys(obj).length;
while(t > rK.length) {
    var l = null;
    for(var x in keys) {
        if(l && parseInt(keys[x]) < parseInt(l)) {
            l = keys[x];
            k = x;
        }
        if(!l) { // Find Lowest
            var l = keys[x];
            var k = x;
        }
    }
    delete keys[k];
    rK.push(l);
}

for (var i = 0; i < len; i++) {

    k = rK[i];
    rObj.push(obj[k]);
}
return rObj;
}

输出将是一个对象,这些对象按这些数字排序,并且新键从0开始。


1

只是为了简化并使其更清晰,Matt Ball的回答

//your object
var myObj = {
    b : 'asdsadfd',
    c : 'masdasaf',
    a : 'dsfdsfsdf'
  };

//fixed code
var keys = [];
for (var k in myObj) {
  if (myObj.hasOwnProperty(k)) {
    keys.push(k);
  }
}
keys.sort();
for (var i = 0; i < keys.length; i++) {
  k = keys[i];
  alert(k + ':' + myObj[k]);
}


1

不知道这是否能回答问题,但这就是我所需要的。

Maps.iterate.sorted = function (o, callback) {
    var keys = Object.keys(o), sorted = keys.sort(), k; 
    if ( callback ) {
            var i = -1;
            while( ++i < sorted.length ) {
                    callback(k = sorted[i], o[k] );
            }
    }

    return sorted;
}

称为:

Maps.iterate.sorted({c:1, b:2, a:100}, function(k, v) { ... } ) 

1

一行:

Object.entries(unordered)
  .sort(([keyA], [keyB]) => keyA > keyB)
  .reduce((obj, [key,value]) => Object.assign(obj, {[key]: value}), {})

1

最好的方法是

 const object =  Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})

 //else if its in reverse just do 

 const object = Object.keys(0).reverse ()

您可以先将几乎类似于数组的对象转换为真实数组,然后使用.reverse():

Object.assign([], {1:'banana', 2:'apple', 
3:'orange'}).reverse();
// [ "orange", "apple", "banana", <1 empty slot> ]

原因引起的最后一个空插槽是因为您的第一个索引是1而不是0。您可以使用.length--或.pop()删除空插槽。

另外,如果您想借用.reverse并在同一对象上调用它,则它必须是一个类似于数组的对象。也就是说,它需要一个length属性:

Array.prototype.reverse.call({1:'banana', 2:'apple', 
3:'orange', length:4});
// {0:"orange", 1:"apple", 3:"banana", length:4}

注意,它将返回相同的全数组对象对象,因此它不是真正的数组。然后,您可以使用delete删除length属性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.