12

我想在给定对象项的情况下向上和向下导航 JavaScript 对象。一个示例对象:

var items = {
   "5" : ["name", "link2"],
   "8" : ["name 2", "link 2"],
   "11" : ["name 3", "link 3"]
}

现在,鉴于我有 item items["8"]。我想分别获得上一个和下一个项目。

getItemBefore = function(index) {
    // index holds 8
    // should return "5"
}

getItemAfter = function(index) {
    // index hold 8
    // should return 11
}

我怎样才能得到这些物品?

4

4 回答 4

12

The keys that an object holds can be retrieved as an array with Object.keys(<var>). The order of the keys in the array is arbitrary; you need to sort them before indexing. An option is the built-in sort() method for arrays, which is especially useful because custom comparison functions can be provided (see below). Default order is alphabetical.

Once you get the ordered array, you only need to look up where your item is in the array and return the next and previous elements from it:

var keys = Object.keys(items).sort();
var loc = keys.indexOf(item);

Given that loc > -1 (that is, the item exists):

  • Previous item: items[keys[loc-1]], but check that loc > 0 (it's not the first one).
  • Next item: items[keys[loc+1]], but check that loc < keys.length (it's not the last one).

Object.keys is compatible with Javascript 1.85+; here is a workaround for older browsers.

Alternative orderings

Numerical

If you want the keys to have a numerical order, use this comparison function:

var keys = Object.keys(items).sort( function(a,b) {
    return b - a;
});

Creation (or Modification) Time

If you want to work with creation order instead of alphanumeric, the items must hold their creation time. Something like:

<value>.index = Date.getTime();
items['<item>'] = <value>;

Then, the sort() method needs the following comparison function:

var keys = Object.keys(items).sort( function(a,b) {
    return b.index - a.index;
});

This can be easily extended to last modification ordering or similar.

Creation Order

Notice that the former solution only works if the items are created more than 1 ms apart, which would be suitable for user actions. If the items are added faster, use this instead of the timestamp:

<value>.index = Object.keys(items).length;

Or, alternatively, keep an external counter with the number of items in the object.

于 2013-03-03T11:55:09.690 回答
3

此答案基于@lemonzi的答案,请参阅他的答案以获取更详细的解释。

我只是想为每个为此苦苦挣扎的人添加一个工作示例:

var items = {
  "5": ["name", "link2"],
  "8": ["name 2", "link 2"],
  "11": ["name 3", "link 3"]
};

var getItem = function(key, i) {
  var keys = Object.keys(items).sort(function(a,b){return a-b;});
  var index = keys.indexOf(key);
  if ((i==-1 && index>0) || (i==1 && index<keys.length-1)) {index = index+i;}
  return items[keys[index]];
}

console.log(getItem("8",-1));
console.log(getItem("8",+1));
jsfiddle:https ://jsfiddle.net/p09yL01f/3/

  • 这样,您只需要一个功能即可更改项目。
  • .sort(function(a,b){return a-b;}) 数组 numeric 进行排序
  • 检查该if ((i==-1 && index>0) || (i==1 && index<keys.length-1)) {项目是否不是数组中的第一个或最后一个索引,如果是,则返回索引本身。

如果要在项目是第一个或最后一个时显示消息,请改用:

if ((i==-1 && index>0) || (i==1 && index<keys.length-1)) {return items[keys[index+i]];}
else {return (i==1?"last":"first")+" item";}

var items = {
  "5": ["name", "link2"],
  "8": ["name 2", "link 2"],
  "11": ["name 3", "link 3"]
};

var getItem = function(key, i) {
  var keys = Object.keys(items).sort(function(a,b){return a-b;});
  var index = keys.indexOf(key);
  if ((i==-1 && index>0) || (i==1 && index<keys.length-1)) {return items[keys[index+i]];}
  else {return (i==1?"last":"first")+" item";}
}

console.log(getItem("5",-1));
console.log(getItem("11",+1));
jsfiddle:https ://jsfiddle.net/p09yL01f/4/

于 2016-11-12T16:18:15.153 回答
2

This is a bit tricky, because technically according to the ECMAScript specifications, the order of properties in an object is implementation specific. That means there's no guarantee in the language that your properties will be in the same order each time you access them. If you're relying on that, there's a potential there could be a problem.

See this bug in Chrome. It states that Chrome doesn't promise to return your keys in any particular order, and it's been marked "WONTFIX" for 4-5 years now. That means that you can't rely on that behavior in Chrome, and here's another post indicating that now IE9 has the same "issue".

So, I would recommend that you create your own object to manage your keys, and use a JavaScript object behind the scenes to store your keys.

Here's something I threw together, it doesn't support deletes and it has no bounds checking, but it should serve your purposes. Fiddle here.

function orderedObject()
{
     this.keys = [];
     this.keyIndex = {};
     this.store = {};
}


orderedObject.prototype.addItem = function(key,value)
{
     this.keyIndex[key] = this.keys.length;
     this.keys.push(key);
     this.store[key] = value;
}

orderedObject.prototype.getItem = function(key)
{
     return this.store[key];
}

orderedObject.prototype.getKeyBefore = function(key)
{
     return this.keys[this.keyIndex[key] - 1];
}

orderedObject.prototype.getKeyAfter = function(key)
{
     return this.keys[this.keyIndex[key] + 1];
}

var testObject = new orderedObject();

testObject.addItem("5" , ["name", "link2"]);
testObject.addItem("8" , ["name 2", "link 2"]);
testObject.addItem("11" , ["name 3", "link 3"]);

console.log(testObject.getKeyBefore("8"))
console.log(testObject.getKeyAfter("8"))
于 2013-03-03T11:48:32.713 回答
1

对象数组在这里更合适吗?下面的示例可以包装在一个对象中并制作 nextItem() 和 prevItem() 方法。有了这个,您可能还需要一些边界检查。

var items = [];
items[0] = {index : '5', name : 'name', link : 'link2'};
items[1] = {index : '8', name : 'name 2', link : 'link 2'};
items[2] = {index : '11', name : 'name 3', link : 'link 3'};

//then access them like this
var nextItem = function (index) {
    var i = 0,
    max = items.length;

    for (i; i < max; i += 1) {
        if (items[i].index === index) {
            return items[i + 1];
        }
    }
    return 'not found';
};

var prevItem = function (index) {
    var i = 0,
    max = items.length;

    for(i; i < max; i += 1) {
        if (items[i].index === index) {
            return items[i - 1];
        }
    }
    return 'not found';
};

//the nextItem object after 5 is shown in the console. 
console.dir(nextItem('5'));
于 2013-03-03T12:32:15.777 回答