While testing out jPaq v2.0 in IE6 on GoToChrisWest.com, I found an IE6 bug (go figure). The issue can be illustrated with the following code:


// Create an object literal with the toString function overwritten.
var obj = {
  toString : function() {
    return "Object ID " + Math.random();
  }
};

// Enumerate all of the properties of obj which should only be "toString".
for(var key in obj) {
  alert(key);
}

The above code should display one thing in the alert box: toString. Unfortunately, when you run the above code in IE6, nothing is displayed to the user. Naturally, the next question that some may think is, what is wrong with that? The problem is, this means that you can not reliably use a for...in loop to loop through all of the explicitly defined properties and functions of an object. This also means, you can’t reliably use jQuery’s or jPaq’s extend function to change an arbitrary property of an object. According to one page, jQuery has fixed the issue for the toString property, but what about these: constructor, hasOwnProperty, isPrototypeOf, toLocaleString, and valueOf? Believe it or not, these are also properties that IE6 seems to ignore.

With this in mind, for the next version of jPaq, I have defined Object.keys (if it isn’t already natively supported) so that it will also check for the previously mentioned keys. The following is the definition that I am using:


// Only define Object.keys if it doesn't exist.
Object.keys = Object.keys || (function() {
  // This is an IE fix.
  var unenumerableKeys = "constructor,hasOwnProperty,isPrototypeOf,toLocaleString,toString,valueOf".split(",");
  for(var key, o = {}, i = 0; key = unenumerableKeys[i]; i++) {
    o[key] = i;
    for(key in o) {
      unenumerableKeys.splice(i--, 1);
      delete o[key];
    }
  }
  
  // Definition for hasOwnerProperty() because it may be overwritten in the object.
  var hasOwnProperty = Object.prototype.hasOwnProperty;

  // The definition for Object.keys().
  return function(obj) {
    if(obj == null) {
        throw new Error("Object.keys called on non-object.");
    }
    var keys = unenumerableKeys.slice(0);
    for(var key in obj) {
      keys.push(key);
    }
    for(var ret = [], i = 0; key = keys[i]; i++) {
      if(hasOwnProperty.call(obj, key))
        ret.push(key);
    }
    return ret;
  };
})();

Now by using Object.keys, I am ensuring that jPaq’s extend function will always work as expected. In addition, when people download the next version of jPaq, they too will be able to rely on an implementation of Object.keys that will always return the keys of the properties for the specified object.

Categories: BlogJavaScriptJScript

Leave a Reply

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