Sunday, February 8, 2009

Creating closures in JavaScript loops

JavaScript has closures, but only one per loop. If you e.g. try this:


for (i in categories) {
category = categories[i];
var menuItem = new dijit.MenuItem({
label: category.name,
onClick: function(){
dojo.query("#currentCategoryId").attr('value', category.id);
categoryButton.attr('label', category.name);
};
});
}


then there will be only one closure for the whole loop, which means all menu items have the same callback using the last values in the categories array.

The workaround is to create the closure in another function, in which case the closure is created in the context of a different stack trace each time.


for (i in categories) {
category = categories[i];
var menuItem = new dijit.MenuItem({
label: category.name,
onClick: createCallback(category.name, category.id, categoryButton)
});
}

/* .... */

function createCallback(name, id, categoryButton) {
return function(){
dojo.query("#currentCategoryId").attr('value', id);
categoryButton.attr('label', name);
};
}

No comments: