也就是说,Underscore的 sortBy 基本上是 Schwartzian转换与标准JavaScript sort 和Underscore的 pluck 来解开Schwartzian Transform备忘录包装; pluck返回一个数组,所以sortBy也返回一个数组.因此,您最后的_.keys(avatars)调用实际上是在数组上调用 _.keys ;数组的键(又称可枚举属性)是数组的索引,并且是从零开始的连续整数.您使用了错误的数据结构.如果您需要稀疏数组但还需要像数组一样对其进行操作(即对它进行排序),则应将索引放在对象中并使用普通数组和pluck而不是keys:var avatars = [ {idx: 102, userInfo: {buddy_name: 'Avatar102', is_online: 1}}, {idx: 100, userInfo: {buddy_name: 'Avatar100', is_online: 1}}, {idx: 101, userInfo: {buddy_name: 'Avatar101', is_online: 1}}];console.log(_(avatars).pluck('idx'));avatars = _(avatars).sortBy(function(avatar) { return avatar.userInfo.buddy_name.toLowerCase();});console.log(_(avatars).pluck('idx'));演示: http://jsfiddle.net/ambiguous/UCWL2/ 如果您还需要通过idx快速访问,则可以为直接idx访问设置并行对象:var avatars_by_idx = { };for(var i = 0; i < avatars.length; ++i) avatars_by_idx[avatars[i].idx] = avatars[i];然后avatars_by_idx提供您正在寻找的直接访问权限.当然,您必须保持avatars和avatars_by_idx同步,但是如果将它们都隐藏在一个对象后面,这并不是很困难.I am trying to avoid writing my own sorting algorithm for the following use case:avatars = {};avatars[102] = {userInfo: {buddy_name: 'Avatar102', is_online: 1}};avatars[100] = {userInfo: {buddy_name: 'Avatar100', is_online: 1}};avatars[101] = {userInfo: {buddy_name: 'Avatar101', is_online: 1}};console.log(_.keys(avatars));avatars = _.sortBy(avatars, function(avatar) {return avatar.userInfo.buddy_name.toLowerCase();});console.log(_.keys(avatars));Here's the console output:["102", "100", "101"]["0", "1", "2"]As you can see, with undescore's sortBy I am losing the key data. This struct can get very large, so I am trying to avoid things like converting to an array and then back to the collection. Is there any way to do this without rolling my own sort function? 解决方案 Your avatars is not an Array, it is just an object:avatars = {};so there is no defined order for its elements:and 15.2.3.7 (and 15.2.3.14):You can also check section 8.6 to see if there is any mention about the order of properties in an object. The only requirement for ordering of object properties is that if the implementation defines an order anywhere then it has to use that same ordering everywhere but that's a big if. Most implementations probably use insertion order for an object's keys but I can't find anything that requires them to (I'd appreciate a comment if anyone can point out anything in the specs that define any particular order of an object's keys).That said, Underscore's sortBy is basically a Schwartzian Transform combined with a standard JavaScript sort and Underscore's pluck to unwrap the Schwartzian Transform memo wrappers; pluck returns an array so sortBy also returns an array. Hence, your final _.keys(avatars) call is actually calling _.keys on an array; the keys of an array (AKA enumerable properties) are the array's indices and those are consecutive integers starting at zero.You're using the wrong data structure. If you need a sparse array but also need to manipulate it like an array (i.e. sort it), then you should put the indexes inside the objects and use a normal array and pluck instead of keys:var avatars = [ {idx: 102, userInfo: {buddy_name: 'Avatar102', is_online: 1}}, {idx: 100, userInfo: {buddy_name: 'Avatar100', is_online: 1}}, {idx: 101, userInfo: {buddy_name: 'Avatar101', is_online: 1}}];console.log(_(avatars).pluck('idx'));avatars = _(avatars).sortBy(function(avatar) { return avatar.userInfo.buddy_name.toLowerCase();});console.log(_(avatars).pluck('idx'));Demo: http://jsfiddle.net/ambiguous/UCWL2/If you also need quick access by idx then you could set up a parallel object for direct idx access:var avatars_by_idx = { };for(var i = 0; i < avatars.length; ++i) avatars_by_idx[avatars[i].idx] = avatars[i];Then avatars_by_idx provides the direct access you're looking for. Of course, you'd have to keep avatars and avatars_by_idx synchronized but that's not terribly difficult if you hide them both behind an object. 这篇关于如何在JavaScript中对对象集合进行排序而不将其转换为数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 10-20 18:26