Tuesday, January 22, 2008

Extending Native JavaScript Types breaks for in loop

I've read a few posts where JavaScript developers have been weighting different JavaScript libraries such as MooTools, Prototype, JQuery etc. based on their addition of methods to the native Types, such as Object, or Array.

The problem with extending native Types via prototyping is that the custom methods are iterated in the "for in loop".

And example is the best way to show this:

// extends the Native Object
Object.prototype.objMethod = function() {};
Object.prototype.objProperty = function() {};

// an instance of Object
var Obj = {
  myMethod: function() {},
  myProperty: ''
};

// iterate over the properties of Obj
for(var x in Obj) {
  alert(x + ' : ' + Obj[x]);
}

This will give you the result:
myMethod : function() {}
myProperty : 
objMethod : function() {}
objProperty  : 
Try It Notice that you not only iterated over the properties of Obj, but also the (user defined) properties Obj inherits from its constructor, Object.

Now, I've heard/seen a lot of developers complain about this. They have their nice "for in" loops that worked well before, and now they break. Before you start blogging about how bad it is to extend native Types, imagine what JavaScript would be like without it.

Javascript, a land dark and mysterious. Where constructors hide their evil prototype inherited methods from brave instances that must cross the __proto__ in order to see their true properties.
Ok, you get the picture...

A work around

The Object.hasOwnProperty() method differentiates between the properties of an Instance and those inherited from the Constructor.

Lets try our for in loop example again:

// extends the Native Object
Object.prototype.objMethod = function() {};
Object.prototype.objProperty = function() {};

// an instance of Object
var Obj = {
  myMethod: function() {},
  myProperty: ''
};

// iterate over the properties of Obj
for(var x in Obj) {
  if (Obj.hasOwnProperty(x))
    alert(x + ' : ' + Obj[x]);
}

Try It

Notice the new line I've added:

if (Obj.hasOwnProperty(x))
. Now I ask, would you rather be able to choose between inherited and non-inherited methods when iterating via a "for in loop", or not have the choice. I'd rather have that choice.

No comments: