Iterating through the key-value pairs of an object that one has created is a task often executed. In view of this, I wrote the following code as a quick and easy way to iterate through all of the keys using a callback function:

(function(hasOwnProperty, undefined) {
  /**
  * Iterate through the properties of any object.
  * @param {!Object} obj
  *     The object whose properties will be iterated over.
  * @param {!function(this:Object, string, *, !Object): *} callback
  *     Callback that will use the scope parameter as the context.  The first
  *     parameter will be the key of the property.  The second parameter will
  *     be the value of the property.  The third parameter will be the object.
  * @param {?Object=} scope
  *     The object that will be used for the context of each call to the
  *     callback function.
  * @param {?boolean=} mapReturns
  *     If true, each value returned from each call to the callback function
  *     will be used as the new value for the corresponding property.
  * @return {Object}
  *     Returns obj object.
  */
  each = function(obj, callback, scope, mapReturns) {
    // Get all keys to prevent extra iterations.
    var ret, keys = [];
    for(var key in obj) {
      keys.push(key);
    }
    // Iterate over the properties that existed at the beginning of this call.
    var i = 0;
    while(undefined != (key = keys[i++])) {
      if(hasOwnProperty.call(obj, key)) {
        ret = callback.call(scope, key, obj[key], obj);
        if(mapReturns) {
          obj[key] = ret;
        }
      }
    }
    return obj;
  };
})(({}).hasOwnProperty);

The JSDoc pretty much explains it all but basically this function could be used as follows:

// Translation of one to five from english to spanish.
var translations = {
  "one": "uno",
  "two": "dos",
  "three": "tres",
  "four": "cuatro",
  "five": "cinco"
};

// Lists all of the translations and adds the reverse translations.
each(translations, function(english, spanish) {
  console.log(english + ' in spanish is ' + spanish);
  translations[spanish] = english;
});

// Shows the object with all of the original and new translations.
console.log(translations);

You will notice that the above shows that you can iterate throw all of the previously defined properties without seeing any properties that were added to the object during the process. You may think that the extra loop isn’t needed, but according to Mozilla’s page about JavaScript for…in loops it is unknown if newly added properties will be traversed.

Originally I wanted to call this Object.prototype.forEach() or Object.prototype.each(), but when I put it in my project that used Google Maps API, an error was thrown.

One interesting thing about this function is the fact that it is chainable since it returns itself. Personally I feel as if most functions, if they don’t return anything, really should return the object being modified (thus the reason I wrote this snippet). That is one of the many things John Resig did right in jQuery. 8)

Categories: BlogJavaScriptJScript

Leave a Reply

Your email address will not be published. Required fields are marked *