Iterating over JavaScript objects

iterators image

One of the things I love about JavaScript is the fact that objects in JS are really just simple hashes of key/value pairs. What's nice about that is that the keys (properties, members, whatever you want to call them) are enumerable. So of course, we all know what that means, right? Right...you can iterate over JS objects. I mean, we all knew we could iterate over collections of objects, but the object itself? Yeah...its OK...I didn't realize it at first either, but its really nice to be able to do that. Knowing this opens up some nice possibilities, doesn't it?

Lets say, as an example, that you wanted or needed to write your own object extension/mixin functionality. Such a function would need to iterate over a source object in order to copy its members onto the target object, right? Lets take a look at how we might do something like that:

WARNING: This is a rudimentary example for the purpose of demonstrating how to iterate over a JavaScript object, and should NOT be considered to be bug-free, feature-complete nor anywhere near ready for production use. That said...it should work just fine.

(function () {
    var extend = function () {
        if (!arguments.length) {
            return;
        }

        var target = arguments[0],
            sources = arguments.slice(1);

        sources.forEach(function (source) {
            // OK, now we're getting somewhere...
            // This is where we iterate over our object...
            // Lets take a look at that separately...below...
        });
    };

    return extend;
}());

So that's generally what our extend function would look like, without actually having iterated over any of the source objects passed in to it. As mentioned in the comments, just for the sake of isolation and clarity, lets take a look at what the code to iterate over those source objects would look like.

There's more than one way to...

Like most things in JavaScript, there's certainly more than one way to iterate over an object. I'll discuss a few of the more prominent ones that I'm aware of here, just so you're aware of some of your options. Lets start with...

for..in

MDN

for (var prop in source) {  
    target[prop] = source[prop];
}

The key thing to understand about using the for..in approach is that it includes all of the keys on the source object, including the ones in its prototype chain. Its important to understand this so you know what to expect when you use this approach to iterating over an object, depending on what you're trying to do with it. Not necessarily a problem...just something to keep in mind.

If that is an issue for you, and using Object.keys (see below) is not an option, you can check each key as you iterate over the object to see if it is on the prototype or not by using the Object.prototype.hasOwnProperty function (more details here).

if (source.hasOwnProperty(prop)) {  
    target[prop] = source[prop];
}

Like I said...its nice to have options.

_.each

underscore.js documentation for this function

_.each(source, function (value, prop) {  
    target[prop] = value;
});

The obvious thing with this approach is that is dependent on having a reference to underscore.js (or lo-dash if your preferences swing that way). The nice thing about this method is that under the covers underscore (yes, that last reference is specific to underscore, I'm not as familiar with lo-dash, sorry) does some capability checking for you to determine the method it uses to actually iterate over the source object, so in most cases (if not all, I personally have never run into an issue with using this method at all) going this route alleviates any need for concern about environment/runtime issues.

Object.keys

MDN

Object.keys(source).forEach(function (prop) {  
    target[prop] = source[prop];
});

The nice thing about this approach is that, as opposed to using the for..in approach above, Object.keys returns an array of the properties of an object that ignores the prototype chain. So if that is an issue you're running into with using for..in then this could be a nice alternative. One caveat of note however, is that this method is only compatible with JS runtimes that support ECMAScript 5.


If you weren't already aware of this, hopefully you can see some of the power and flexibility options this opens up for your code. I've found it to be really useful in the right situations. If you were aware of it and are using this technique already, what are some of the useful/interesting things you're using it for??