按键排序 JavaScript 对象

Posted

技术标签:

【中文标题】按键排序 JavaScript 对象【英文标题】:Sort JavaScript object by key 【发布时间】:2011-07-24 22:32:46 【问题描述】:

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

因此如下:

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

会变成:

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

【问题讨论】:

Sorting a JSON object in Javascript的可能重复 早在 2011 年(当这个问题发布时),ECMAScript 规范说 JavaScript 对象没有固有的顺序——观察到的顺序是依赖于实现的,因此不能依赖。然而,事实证明all JavaScript engines implemented more or less the same semantics, so those have now been standardized in ES6。因此,根据规范,以下许多答案过去都是正确的,但现在不正确。 简单地说,当您需要比较或散列结果时使用排序的字符串化:npmjs.com/package/json-stable-stringify 鉴于对象只是地图或字典,具体取决于您的语言,您几乎没有理由这样做。话虽如此,一般来说,它们被注入映射的顺序实际上是它们在字符串化时所在的顺序。所以,如果你创建了一个新的映射并根据预排序的键列表分配值,你会发现自己是一个基于键的有序映射 请注意,自从 Object.entriesObject.fromEntries 被添加到 JS 之后,这可以通过非常短的一行来实现:Object.fromEntries(Object.entries(obj).sort()) 【参考方案1】:

这个问题的其他答案已经过时,与实现实际不匹配,并且在 ES6 / ES2015 规范已经发布后,正式变得不正确。


见the section on property iteration order in Exploring ES6 by Axel Rauschmayer:

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

    首先是所有数组索引,按数字排序。 然后是所有字符串键(不是索引),按照它们的创建顺序。 然后是所有符号,按照它们的创建顺序。

所以是的,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().reduce(
  (obj, key) =>  
    obj[key] = unordered[key]; 
    return obj;
  , 
  
);

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

使用 var 代替 const 以与 ES5 引擎兼容。

【讨论】:

除了使用稍微不同的循环技术之外,我真的看不出您的代码和最佳答案有什么不同。对象是否可以说是“有序的”似乎无关紧要。这个问题的答案还是一样的。发布的规范只是在这里确认了答案。 仅供参考,已澄清 enumeration 属性的顺序仍未定义:esdiscuss.org/topic/… @Phil_1984_ 这个答案和票数最高的答案非常不同。 OP 的问题是如何对对象文字进行排序。投票最多的答案说你不能,然后通过将排序的键存储在数组中,然后从排序的数组中迭代和打印键值对来提供解决方法。这个答案声称对象文字的顺序现在是可排序的,他的示例将排序的键值存储回对象文字,然后直接打印排序的对象。顺便说一句,如果链接的网站仍然存在,那就太好了。 两个答案都简单地使用 Array.sort 函数首先对键进行排序。 OP 要求对“JavaScript 对象”进行排序,并且仅使用 JavaScript 对象表示法 (JSON) 来描述这 2 个对象。这两个对象在逻辑上是相同的,这意味着排序是不相关的。我认为最佳答案更好地解释了这一点。说“所有其他答案现在正式不正确”对我来说太极端了,尤其是在链接断开的情况下。我认为问题在于“这个新的 ES6 规范”给人一种错觉,即 Javascript 对象有一个有序的键列表,这根本不是真的。 请补充一下,各种现代浏览器(谷歌“caniuse ES6”)不支持此解决方案。使用此答案可能仅在某些浏览器中难以发现错误(例如,当 Chrome 一切正常时使用 Safari)。【参考方案2】:

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 fanciness 的替代实现:

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不要学究气,而是there's no such thing as a JSON object。

【讨论】:

@MarcelKorpel 有 JSON 对象之类的东西。查看官方 JSON RFC 的第 8 节:ietf.org/rfc/rfc4627.txt @Paulpro 关于该 RFC 需要注意两点:首先,此时它已经 7 年了,词汇随着时间的推移而变化;其次,“本备忘录为互联网社区提供信息。它没有指定任何类型的互联网标准。” 给定的字符序列是表示 JavaScript 对象文字还是 JSON 文本取决于上下文/用法。术语“JSON 对象”混为一谈,并以有害的方式使区别变得模糊。让我们摆脱不精确的术语,并尽可能使用更精确的术语。我认为没有理由不这样做。文字很重要。 @MattBall IMO JSON 对象是 "a", 1 这样的字符串的精确术语,就像 JSON 数组是 [1] 这样的字符串的精确术语一样。当你有字符串 [x: 1, y: 2, z: 3] 时,通过说出我的数组中的第三个对象之类的东西来进行交流很有用,所以在评论 Javascript 文字时我更喜欢“这不是 JSON 对象”,而不是“那里不是 JSON 对象之类的东西”,这只会在 OP 实际使用 JSON 时造成更多的混乱和沟通困难。 @Paulpro 我一定不同意。 "a", 1 是对象文字或 JSON 文本(也称为 JSON 字符串,如果您愿意的话)。它取决于上下文,前者如果它在 JavaScript 源代码中逐字出现,后者如果它是一个需要传递给 JSON 解析器以供进一步使用的字符串。在允许的语法、正确用法和序列化方面,两者之间存在真正的差异。 既然 ES6/ES2015 已经敲定,这个答案正式成为错误的答案。 See my answer for more info.【参考方案3】:

很多人都提到“对象无法排序”,但之后他们会为您提供一个可行的解决方案。悖论,不是吗?

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

我认为我们可以再添加一个解决方案——ES5 函数式方式:

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

上面的ES2015版本(格式化为“one-liner”):

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

上述例子的简短解释(在 cmets 中询问):

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

【讨论】:

@Pointy 这种行为在所有主流浏览器中始终可用,has been standardized in ES6/ES2015。我会说这是个好建议。 这是 EcmaScript v5 中最简单、最简洁的完成任务的方式。聚会有点晚了,但应该是公认的答案。 “它们是,因为在大多数浏览器的实现中,对象中的值是按照它们添加的顺序存储的” 仅适用于非数字属性。另请注意,仍然无法保证迭代属性的顺序(例如通过for...in)。 很高兴您能解释它为什么有效,它为我上了一课。谢谢! 我的 linter 抱怨那条线(返回作业),但这条线对我有用,而且我更容易阅读:Object.keys(dict).sort().reduce((r, k) =&gt; Object.assign(r, [k]: dict[k] ), );【参考方案4】:

伙计们,我很震惊!当然所有的答案都有些老了,但没有人提到排序的稳定性!所以请耐心等待,我会尽力回答问题本身并在此处详细介绍。所以我要道歉,现在要读的东西很多。

由于是 2018 年,我将只使用 ES6,所有 Polyfill 都可以在 MDN 文档中找到,我将在给定部分链接。


问题答案:

如果您的键只是数字,那么您可以安全地使用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), ));

如果有人想知道 reduce 是做什么的:

// 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.
  ,
);
减少文档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce 为什么在 JavaScript 返回语句中使用括号:http://jamesknelson.com/javascript-return-parenthesis/

为什么排序有点复杂:

简而言之,Object.keys() 将返回一个与我们在正常循环中得到的顺序相同的数组:

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

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

Object.keys() 返回一个元素为字符串的数组 对应于直接在对象上找到的可枚举属性。 属性的顺序与循环给出的顺序相同 手动覆盖对象的属性。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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 码位。

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

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

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


那么有什么大不了的?

有两篇文章是每个程序员都应该了解的:

In-place algorithm:

在计算机科学中,就地算法是一种不使用辅助数据结构来转换输入的算法。然而,辅助变量允许有少量的额外存储空间。当算法执行时,输入通常被输出覆盖。就地算法仅通过替换或交换元素来更新输入序列。不就地的算法有时称为不就地或不就地。

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

Sorting algorithm

稳定的排序算法以相同的顺序对相同的元素进行排序 它们出现在输入中。对某些类型的数据进行排序时,只有一部分 在确定排序顺序时会检查数据。例如, 在右边的卡片分类示例中,卡片正在被分类 按他们的等级,他们的西装被忽略了。这允许 多个不同的正确排序版本的可能性 原始清单。稳定的排序算法选择其中之一, 根据以下规则:如果两个项目比较相等,例如 两张5张牌,那么它们的相对顺序将被保留,这样 如果输入中一个在另一个之前,它也会在 另一个在输出中。

扑克牌稳定排序的一个例子。卡片分类时 按排名稳定的排序,两个 5 必须保持相同的顺序 在它们最初所在的排序输出中。当它们在 使用不稳定排序进行排序,5s 可能以相反的顺序结束 在排序后的输出中。

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

【讨论】:

你的摇滚,谢谢你这个令人难以置信的答案。我在 SO 上见过的最好的之一。干杯。 如果你能在最后提供一个可怕的方法。不过答案很好! @momomo 问题是,根据您对排序的期望,没有正确的方法。但是,您可以简单地使用我的回答中的这段代码:Object.keys(testObj).sort().reduce((a, c) =&gt; (a[c] = testObj[c], a), ) 排序的稳定性是否不适用于这个问题:我们是按对象键排序,键是唯一的。 (扩展你的卡片示例:一副 5 永远不可能有两个,即使它们的花色不同。) @DarrenCook 好问题!你是对的,一个对象中永远不会有相同的键。然而,稳定性比密钥的唯一性更复杂。大多数时候,数组包含在排序对象中。那就是一切都变得不稳定的时候。想象一个有 5 名玩家的纸牌游戏。每只手都由一个数组表示(以保持单独的手排序),并将卡片作为对象。如果您的卡片看起来像 5: 'hearts'5: 'spades' 并且您开始对数组进行排序,那么它在拉米游戏等游戏中可能会变得不稳定。不要说不同的语言。【参考方案5】:

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

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

【讨论】:

我们如何按键排序嵌套对象? @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)) 对于 TypeScript 用户,我们还不能使用它,请参阅:github.com/microsoft/TypeScript/issues/30933 不错的单行,但是如何以不区分大小写的方式对键进行排序? @theMaxx 使用自定义函数进行排序,例如:``` Object.fromEntries(Object.entries(b: 3, a:8, c:1).sort(([ key1, val1], [key2, val2]) => key1.toLowerCase().localeCompare(key2.toLowerCase()))) ``【参考方案6】:

ES6 - 这是 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 here short 函数首先使o[k] 等于v 然后返回o 这个解决方案很重 - 它将条目数组转换为字符串。并且不适用于任意键,例如Object.entries( a: 8, ['a,1']: 6 ).sort() -> [ [ 'a,1', 6 ], [ 'a', 8 ] ]【参考方案7】:

这对我有用

/**
 * 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;
;

【讨论】:

这实际上是手头问题的正确答案。有关使用下划线的简化版本,请参阅:jsfiddle.net/wPjaQ/1 @radicand 不,这个答案不正确。它返回一个新对象,它也没有顺序。 @radicand 实际上也没有。对象键上没有顺序之类的东西,所以你怎么能说在实践中这给了你一个按排序顺序的对象?它实际上只是为您提供了传入对象的浅表副本。 这是大错特错。它现在可能会起作用,但会在不同的网络浏览器中中断或在同一浏览器中加载不同的页面。浏览器可能会随机化对象键以确保安全,或者当您填充对象时,它会根据键将值放入不同的内存桶中,这将返回不同的顺序。如果这碰巧奏效了,那对你来说是幸运的。 它还有一个不必要的jQuery使用。【参考方案8】:

这是一个老问题,但从 Mathias Bynens 的回答中得到启发,我制作了一个简短的版本来对 current 对象进行排序,没有太多开销。

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

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

【讨论】:

天啊天啊。正是我想要的。在对对象进行操作时,我通常更喜欢通过引用对它们进行操作,因此返回新对象的解决方案并不理想。非常感谢。我欠你一杯咖啡/茶/啤酒/来世的拥抱:-P【参考方案9】:

使用 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();

只是思考的食物。

【讨论】:

【参考方案10】:

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

(function(s) 
    var t = ;

    Object.keys(s).sort().forEach(function(k) 
        t[k] = s[k]
    );

    return t
)(
    b: 2,
    a: 1,
    c: 3
);

同内联版:

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

【讨论】:

太好了,谢谢 loooot 不错!感谢您提供这个简洁的解决方案。【参考方案11】:

实际上,我很惊讶给出了 30 多个答案,但没有一个为这个问题提供完整的 deep 解决方案。有些解决方案很浅,而有些解决方案很深但有缺陷(如果未定义会崩溃,函数或符号将在 json 中)。

这里是完整的解决方案:

function sortObject(unordered, sortArrays = false) 
  if (!unordered || typeof unordered !== 'object') 
    return unordered;
  

  if (Array.isArray(unordered)) 
    const newArr = unordered.map((item) => sortObject(item, sortArrays));
    if (sortArrays) 
      newArr.sort();
    
    return newArr;
  

  const ordered = ;
  Object.keys(unordered)
    .sort()
    .forEach((key) => 
      ordered[key] = sortObject(unordered[key], sortArrays);
    );
  return ordered;


const json = 
  b: 5,
  a: [2, 1],
  d: 
    b: undefined,
    a: null,
    c: false,
    d: true,
    g: '1',
    f: [],
    h: ,
    i: 1n,
    j: () => ,
    k: Symbol('a')
  ,
  c: [
    
      b: 1,
      a: 1
    
  ]
;
console.log(sortObject(json, true));

【讨论】:

对我来说也一样!我滚动浏览以找到问题的深层解决方案(在发布我自己的答案之前,这与您的答案相同)。但后来我看到了你的,并赞成。 :)【参考方案12】:

Underscore version:

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))【参考方案13】:
function sortObjectKeys(obj)
    return Object.keys(obj).sort().reduce((acc,key)=>
        acc[key]=obj[key];
        return acc;
    ,);


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

【讨论】:

也许对你的代码添加一些解释会更好。 获取对象的键,所以它是字符串数组,我对它们进行排序(),因为它是字符串(键)数组,所以我减少它们(使用 js 数组的 reduce())。 acc 最初是一个空对象 (reducer 的最后一个参数),reducer(回调)使用有序键序列为空对象分配源 obj 的值。【参考方案14】:

也许更优雅一点的形式:

 /**
     * 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  
));

附:与 ES6+ 语法相同:

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

【讨论】:

这没什么。你仍然返回一个对象。你不能保证你的目标中的对象实际上会有任何顺序。你需要返回一个数组。天哪。 您在这里唯一要做的就是确保它是一组,以非最佳方式。【参考方案15】:

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

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; var sortKeys = (unordered) => function srt(obj) const isAr = Array.isArray(obj) return !isAr && typeof obj === 'object' ? Object.keys(obj).sort().reduce((a,k)=> let vl = obj[k] let isArr = Array.isArray(vl) if (isArr) vl = vl.map(srt) if (vl && typeof vl === 'object' && !isArr) a[k]=srt(vl) else a[k]=vl return a; ,) : (isAr ? obj.map(srt) :对象); console.log(JSON.stringify(srt(unordered), null, 4)) 以上可以帮助保存数组,以及在您的解决方案中,数组正在转换为类似数组的对象 此解决方案在某些情况下可以将数组转换为对象。 (例如,数组中的数组)【参考方案16】:

这是一个单行解决方案(不是最有效的,但是当涉及到像您的示例中那样的瘦对象时,我宁愿使用本机 JS 函数,然后搞乱草率的循环)

const unordered =  'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' 

const ordered = Object.fromEntries(Object.entries(unordered).sort())

console.log(ordered); // a->b->c

【讨论】:

【参考方案17】:

这是一个干净的基于 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() method 会更干净...

【讨论】:

【参考方案18】:
Object.keys(unordered).sort().reduce(
    (acc,curr) => (...acc, [curr]:unordered[curr])
    , 
)

【讨论】:

如果你没有为了清楚起见而打破它,这可能适合 SO 上的单行,对于循环海洋中的单行,这值得更多信任。很好地使用扩展运算符进行合并,我一直都是这样做的,但是分配然后返回,所以从解决方案中学到了一些东西:)【参考方案19】:
// if keys are char/string
const sortObject = (obj) => Object.fromEntries(Object.entries(obj).sort( ));
let obj =  c: 3, a: 1 ;
obj = sortObject(obj)

// if keys are numbers
const sortObject = (obj) => Object.fromEntries(Object.entries(obj).sort( (a,b)=>a-b ));
let obj =  3: 'c', 1: 'a' ;
obj = sortObject(obj)

【讨论】:

【参考方案20】:

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

不过……

你可能会发现这个成语很有用:

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' ] ]

【讨论】:

In reality and in ES6 objects are ordered.【参考方案21】:

@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

【讨论】:

【参考方案22】:

如果您有嵌套对象或嵌套数组 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;
;

【讨论】:

作者没有说他正在使用 jQuery,也没有标记 jQuery。如果您在纯 javascript 中添加解决方案会很好。 感谢@Phani,这正是我所需要的【参考方案23】:

只需使用 lodash 解压缩 map 和 sortBy 对的第一个值并再次 zip 它将返回排序键。

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

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

【讨论】:

请使用edit链接解释这段代码是如何工作的,不要只给出代码,因为解释更有可能帮助未来的读者。另见How to Answer。 source【参考方案24】:

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

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

【讨论】:

不错的sn-p!那里delete o[e[0]]; 的目的是什么?我们不能分配吗? 似乎只有对不存在的键的新分配才会在最后附加键。如果删除被注释掉,键不会被排序,至少在 Chrome 中不会。 这是有道理的。谢谢!无论如何,根据规范,这是一个失败的原因,因为 js 对象键没有顺序。我们只是在利用 obj 和 log 函数 impl 详细信息 是的,当键的顺序很重要时,我使用 Map:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…【参考方案25】:

这是我对 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;
    , );

【讨论】:

警告:这不仅对键进行排序,还对数组项进行排序!【参考方案26】:

解决方案:

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;
  ;

【讨论】:

【参考方案27】:

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

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

var Helper = 
    isEmpty: function (obj) 
        return !obj || obj === null || obj === undefined || Array.isArray(obj) && obj.length === 0;
    ,

    isObject: function (obj) 
        return (typeof obj === 'object');
    ,

    sortObjectKeys: function (object) 
        return Object.keys(object)
            .sort(function (a, b) 
                c = a - b;
                return c
            );
    ,
    containsItem: function (arr, item) 
        if (arr && Array.isArray(arr)) 
            return arr.indexOf(item) > -1;
         else 
            return arr === item;
        
    ,

    pushArray: function (arr1, arr2) 
        if (arr1 && arr2 && Array.isArray(arr1)) 
            arr1.push.apply(arr1, Array.isArray(arr2) ? arr2 : [arr2]);
        
    
;

function TypeHelper() 
    var _types = arguments[0],
        _defTypeIndex = 0,
        _currentType,
        _value;

    if (arguments.length == 2) 
        _defTypeIndex = arguments[1];
    

    Object.defineProperties(this, 
        Key: 
            get: function () 
                return _currentType;
            ,
            set: function (val) 
                _currentType.setType(val, true);
            ,
            enumerable: true
        ,
        Value: 
            get: function () 
                return _types[_currentType];
            ,
            set: function (val) 
                _value.setType(val, false);
            ,
            enumerable: true
        
    );

    this.getAsList = function (keys) 
        var list = [];
        Helper.sortObjectKeys(_types).forEach(function (key, idx, array) 
            if (key && _types[key]) 

                if (!Helper.isEmpty(keys) && Helper.containsItem(keys, key) || Helper.isEmpty(keys)) 
                    var json = ;
                    json.Key = key;
                    json.Value = _types[key];
                    Helper.pushArray(list, json);
                
            
        );
        return list;
    ;

    this.setType = function (value, isKey) 
        if (!Helper.isEmpty(value)) 
            Object.keys(_types).forEach(function (key, idx, array) 
                if (Helper.isObject(value)) 
                    if (value && value.Key == key) 
                        _currentType = key;
                    
                 else if (isKey) 
                    if (value && value.toString() == key.toString()) 
                        _currentType = key;
                    
                 else if (value && value.toString() == _types[key]) 
                    _currentType = key;
                
            );
         else 
            this.setDefaultType();
        
        return isKey ? _types[_currentType] : _currentType;
    ;

    this.setTypeByIndex = function (index) 
        var keys = Helper.sortObjectKeys(_types);
        for (var i = 0; i < keys.length; i++) 
            if (index === i) 
                _currentType = keys[index];
                break;
            
        
    ;

    this.setDefaultType = function () 
        this.setTypeByIndex(_defTypeIndex);
    ;

    this.setDefaultType();



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"
;
console.log('keys of TypeA', Helper.sortObjectKeys(TypeA));//keys of TypeA ["-1", "2", "100", "200", "1000"]

console.log('keys of TypeB', Helper.sortObjectKeys(TypeB));//keys of TypeB ["U", "W", "V", "A", "Z", "K"]

var objectTypeA = new TypeHelper(TypeA),
    objectTypeB = new TypeHelper(TypeB);

console.log('list of objectA = ', objectTypeA.getAsList());
console.log('list of objectB = ', objectTypeB.getAsList());
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"]

【讨论】:

【参考方案28】:

一行:

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

【讨论】:

【参考方案29】:

对对象进行排序的纯 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 开始。

【讨论】:

【参考方案30】:

简单易读的 sn-p,使用 lodash。

只有在调用 sortBy 时才需要将键放在引号中。它不必在数据本身的引号中。

_.sortBy(myObj, "key")

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

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

【讨论】:

_.sortBy(myObj, "key") 将按属于集合项的键(即myObj.item.key)而不是myObj 本身(myObj.item,其中'item' 是一个对象)对集合进行排序。

以上是关于按键排序 JavaScript 对象的主要内容,如果未能解决你的问题,请参考以下文章

Javascript/Coffeescript 在值相同时对多个键上的对象数组进行排序

如何按键排序对象数组?无法正确处理

十大经典排序算法

无法重置布尔值 - Javascript

如何在javascript对象中按键查找对象?

如何通过D3.js中的JSON文件解析按键对对象进行排序[重复]