19
var obj = { 'a' : 'apple', 'b' : 'banana', 'c' : 'carrot' }

If I do a

for (var key in obj) {
  console.log( key + ' has a value ' + obj[key] );
}

It will look through all the values in obj. If I have a much larger object, how do I know if I am on the last iteration of that for loop?

I realize that key value pairs aren't really organized in order, but I need to accomplish something in the very last iteration of this loop and don't know how.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Joshua Soileau
  • 2,933
  • 9
  • 40
  • 51
  • possible duplicate of [How to get object length in jQuery](http://stackoverflow.com/questions/5533192/how-to-get-object-length-in-jquery) – Roko C. Buljan Jan 12 '14 at 15:55
  • 1
    Possible duplicate of [getting the last item in a javascript object](https://stackoverflow.com/questions/4317456/getting-the-last-item-in-a-javascript-object) – Heretic Monkey Jun 05 '19 at 15:55

6 Answers6

43

don't use for (key in obj), it will iterate over all enumerable properties including prototype properties, and can lead to amazingly horrible things. Modern JS has a special function for getting only the relevant keys out of an object, using Object.keys(...), so if you use var keys = Object.keys(obj) to get the list of keys as an array, you can then iterate over that:

// blind iteration
Object.keys(obj).forEach(function(key, i) {
  var value = obj[key];
  // do what you need to here, with index i as position information.
  // Note that you cannot break out of this iteration, although you
  // can of course use ".some()" rather than ".forEach()" for that.
});

// indexed iteration
for(var keys = Object.keys(obj), i = 0, end = keys.length; i < end; i++) {
  var key = keys[i], value = obj[key];
  // do what you need to here, with index i as position information,
  // using "break" if you need to cut the iteration short.
});

or select its last element immediately

var keys = Object.keys(obj);
var last = keys[keys.length-1];

or using a slice:

var keys = Object.keys(obj);
var last = keys.slice(-1)[0];

or using a shift (but that's a destructive operation, so we're not caching the keys because the shift turns it into "not all the keys anymore"):

var last = Object.keys(obj).shift();

2021 edit

There is now also the Object.entries function, which gets you key/value pairs in one go:

Object.entries(obj).forEach(([key, value]) => {
  console.log(`key "${key}" points to:`, value):
});
Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
  • Exactly what I was going to suggest. – T.J. Crowder Jan 12 '14 at 15:55
  • Why should a `Object.keys(obj)` be better then a `for( key in obj) ` with `hasOwnProperty` (I know the `hasOwnProperty` is not in the question) ? `Object.keys` will create a new object holding the keys. – t.niese Jan 12 '14 at 15:57
  • @t.niese Obj.keys() = ECMAScript 5.1 – Roko C. Buljan Jan 12 '14 at 15:58
  • @t.niese you pretty much answered your own question. A single API call that generates the data required is better than a blind iteration that then requires an extra calls for each value found to check whether it's actually the correct value. `Object.keys` might generate a new array, but the time required to do that is far less than the time required to call that `.hasOwnProperty` check for each attribute, and you're not going to see a spike in your memory profile from the arrays created by Object.keys under for-webpage conditions (for-custom-engines conditions are a different beast) – Mike 'Pomax' Kamermans Jan 12 '14 at 16:05
  • 1
    @Mike'Pomax'Kamermans ok yes, just did a little test and it performs way better then the last time I tested it. Engines got better in creating the list at once and probably also handles it in a way that they only do a real memory allocation if array is modified, at least V8 seems to do a really great job here. – t.niese Jan 12 '14 at 16:34
  • why foreach and not map? – haemse Jul 20 '17 at 08:00
  • because the original question shows nothing that requires mapping. – Mike 'Pomax' Kamermans Jul 20 '17 at 17:42
4

You could loop through all of them and save the last one in a variable.

var lastItem = null;
for(var key in obj) {
  console.log( key + ' has a value ' + obj[key] );
  lastItem = key;
}
// now the last iteration's key is in lastItem
console.log('the last key ' + lastItem + ' has a value ' + obj[lastItem]);

Also, because of how JavaScript works the key is also in your loop's key variable, so the extra variable is not even needed.

for(var key in obj) {
  console.log( key + ' has a value ' + obj[key] );
}
// now the last iteration's key is in key
console.log('the last key ' + key + ' has a value ' + obj[key]);
PurkkaKoodari
  • 6,703
  • 6
  • 37
  • 58
3

just shorter

var last = (last=Object.keys(json))[last.length-1];
ceed
  • 689
  • 1
  • 6
  • 15
0

You could put the logic for the last item outside the loop:

var last_item = null;
for (var key in obj) {
  last_item = key;
}
console.log(last_item);
ggorlen
  • 44,755
  • 7
  • 76
  • 106
hugomg
  • 68,213
  • 24
  • 160
  • 246
-1

You could push all of the keys/values into a a empty array variable that you created. Then, access the last element in the array using array.length-1.

  • This is a huge waste of memory. If you have an object with a million entries, you hit the heap to create a million-element array, then toss the whole thing to the garbage collector immediately just to get one element from it. Other answers show better approaches that use O(1) memory without sacrificing readability. – ggorlen May 20 '21 at 23:39
-3
for(var x=0 ; x<Object.keys(obj).length ; x++)
{
     if(x==Object.keys(obj).length-1) // code for the last iteration

}

Or could use Object.size(obj)

D. Rattansingh
  • 1,569
  • 3
  • 19
  • 30
  • I don't see why not. Trivial issue, there's always the Object.size(obj) – D. Rattansingh Jan 12 '14 at 16:04
  • This unnecessarily calls `Object.keys` _twice for every element of the array_! One call is all you need, as shown in other answers, O(n) instead of O(n*n). – ggorlen May 20 '21 at 23:38