Monday, June 28, 2010

Evilness Part 1: The Damn Looping

One of the most common cases where the evilness break whatever we coded is when we use for ... in without taking into account what JavaScript does to deal with it.

Look at the following tiny code chunk:

var obj = {
  foo : "Hello",
  bar : function (msg) {
    alert(msg);
  }
};

for (var field in obj) {
  alert(field);
}

The previous code will show two alerts ("foo" and "bar"), as it's expected. Now let's see the following piece of code:

Object.prototype.evil = "Prototype chainevil-ity";

var obj = {
  foo : "Hello",
  bar : function (msg) {
    alert(msg);
  }
};

for (var field in obj) {
  alert(field);
}

This seems to be the same code as the shown above, but it's not. Now it will show three alerts ("foo", "bar" and "evil") because the for...in statement goes through the whole prototype chain.

I mean, if the primitive prototypes are extended with new properties and methods, these new properties and methods will appear in the for...in loop for any instance created from those primitive prototypes.

So, is it possible to safely enumerate properties?. And the answer is yes, it is. JavaScript provides a method named hasOwnProperty that any kind of object or composite type has.

Using this method we can check if an object contains a field in its own instance, without checking the prototype chain. This mean that we are able to deal with this kind of evilness using this method, as it's shown below:

Object.prototype.evil = "Prototype chainevil-ity";

var obj = {
  foo : "Hello",
  bar : function (msg) {
    alert(msg);
  }
};

for (var field in obj) {
  if (obj.hasOwnProperty(field)) {
    alert(field);
  }
}

// Shows an alert saying "Prototype chainevil-ity".
alert(obj.evil);

Yes, it works as the first piece of code but you are still able to use the evil property because it's a member of the object's prototype. This applies both for properties and methods.

And what about using for...in to iterate over a primitive Array? This is another kind of evilness and it will be covered in the next blog entry.

Good luck.

No comments: