Suppose we have a list of simple objects:
var things = [
{ id: 1, name: 'one' },
{ id: 2, name: 'two' },
{ id: 3, name: 'three' }
];
And we need to iterate through these objects and register them as parameters for some later event. The naive approach shares the same object reference between all callbacks, so each fires against the last item:
for (var i = 0; i < things.length; i++) {
var o = things[i];
setTimeout(function() { doSomethingWith(o); }, i * 1000);
}
A typical solution is to create a closure, limiting the scope of our object reference:
for (var i = 0; i < things.length; i++) {
(function() {
var o = things[i];
setTimeout(function() { doSomethingWith(o); }, i * 1000);
})();
}
If we're not targeting IE<9, we could depend on .forEach()
:
things.forEach(function(o, i) {
var o = things[i];
setTimeout(function() { doSomethingWith(o); }, i * 1000);
});
But, we've ultimately created a sort of closure in this case anyway in passing an anonymous function to forEach()
.
Is there a way to accomplish this without a closure or function reference?
The underlying problem is three-fold:
- Less importantly: The function reference passed into
setTimeout()
(or whatever it may be) makes you (me) feel like you're creating a closure. So, I have a tendency to forget the outer closure. - More importantly: The additional function/closure declarations encourage "arrow code." For complex operations, code readability for complex operations pretty quickly deteriorates as code migrates off the screen ... This is potentially addressed by
.forEach()
in IE>9, unless the application or organizational style guide dictates a newline + indent for the closure. - Most importantly: I was pretty sure there was a simple way to handle this. And I feel silly for not being able to think of it right now.
Maybe the better way to ask it is this: What the devil did we all do before we all started compulsively creating closures?