My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Tuesday, March 20, 2007

for in loop prototype safe

In many different libraries there should be one or more prototype method for every native JavaScript constructor.

Every time You do a for in loop
for(var key in object) ...

You probably need to check object[key].

Add prototype to Object constructor is never a good practices, but for in loop can be used with other native constructors too, as example, Array.


Array.prototype.randomValue = function(){
return this[Math.floor(Math.random() * this.length)];
};

var myArray = [1, 2, 3];
alert(myArray.randomValue()); // 1 or 2 or 3


The common way to loop over an array is a loop that uses index integer values but sometime You should need to loop over a generic variable just using a for in loop.


for(var key in myArray) {
// dostuff
}

In this case the "randomValue" key is part of loop but You can't know everytime wich library add its Array prototype so this is my simple proposal, the $for function.

function $for(obj, callback){
var proto = obj.constructor.prototype,
h = obj.hasOwnProperty, key;
for(key in obj) {
if((h && h.call(obj,key)) || proto[key] !== obj[key])
callback(key, obj[key]);
}
};

With these few lines of code You can perform a for in loop without prototype problems, for example:

var myArray = [1, 2, 3],
total = 0;
$for(myArray, function(key, value){
total += value;
});
alert(total);

Used function is automatically cached by $for one so I think this kind of loop will be fast enought (expecially working with internal scope).

Do You like this prototype safe solution? I hope so :)

7 comments:

Unknown said...

Cool idea. Unrelated, I have included a link to your GzOutput.class in the latest release of ProtoPacked (Prototype Compression Pack).

Anonymous said...

i'm used to use this:

for each (fiore in cesta)
{
alert(fiore);
}

is it much different from the $for function you suggested?

Andrea Giammarchi said...

for each is for JavaScript 1.6 or greater, do You write code only for FireFox?

However, You didn't understand the problem, for each gives you the value, not the key, but gives you prototyopes too.

Anonymous said...

You should probably mention that this approach will fail to enumerate over certain keys in IE

Andrea Giammarchi said...

constructor, toString, valueOf ... and if I am not wrong, that's it :)

Anonymous said...

Well, actually, any that shadow Object.prototype.* native ones.

I have a little helper for enumeration, take a look: http://github.com/kangax/protolicious/tree/master/object.for_in.js#L28

Andrea Giammarchi said...

nice one kangax ;)