我需要按键对 JavaScript 对象进行排序。
因此有以下几点:
{ 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' }
会成为:
{ 'a' : 'dsfdsfsdf', 'b' : 'asdsad', 'c' : 'masdas' }
我需要按键对 JavaScript 对象进行排序。
因此有以下几点:
{ 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' }
会成为:
{ 'a' : 'dsfdsfsdf', 'b' : 'asdsad', 'c' : 'masdas' }
这个问题的其他答案已经过时,从未符合实现现实,并且现在 ES6 / ES2015 规范已经发布,正式变得不正确。
请参见上一节物业迭代顺序在探索ES6属于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 引擎兼容。
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 对象这样的东西。
很多人都提到“对象无法排序”,但在那之后他们给了你一个有效的解决方案。悖论,不是吗?
没有人提到为什么这些解决方案有效。它们是,因为在大多数浏览器的实现中,对象中的值是按照它们添加的顺序存储的。这就是为什么如果您从排序的键列表创建新对象,它会返回预期的结果。
而且我认为我们可以再添加一种解决方案——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), {})
上述示例的简短说明(如评论中所问):
Object.keys
正在给我们提供的对象(obj
或o
)中的键列表,然后我们使用默认排序算法对它们进行排序,下一步.reduce
用于将该数组转换回对象,但这次所有键都已排序。
伙计们,我比喻性地震惊了!当然所有的答案都有些老了,但甚至没有人提到排序的稳定性!所以请耐心等待,我会尽力回答问题本身,并在此处详细介绍。所以我现在要道歉,这将是很多阅读。
由于是 2018 年,我将只使用 ES6,Polyfills 都可以在 MDN 文档中找到,我将在给定部分链接。
回答问题:
如果您的键只是数字,那么您可以安全地使用Object.keys()
withArray.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.
,{}
);
为什么排序有点复杂:
简而言之,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/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
现在是 2019 年,我们有 2019 年的方法来解决这个问题:)
Object.fromEntries(Object.entries({b: 3, a:8, c:1}).sort())