JSlint error 'Don't make functions within a loop.' leads to question about Javascript itself
Partially it depends on whether you're using a function expression or a function declaration. They're different things, they happen at different times, and they have a different effect on the surrounding scope. So let's start with the distinction.
A function expression is a function
production where you're using the result as a right-hand value — e.g., you're assigning the result to a variable or property, or passing it into a function as a parameter, etc. These are all function expressions:
setTimeout(function() { ... }, 1000);
var f = function() { ... };
var named = function bar() { ... };
(Don't use that last one — which is called a named function expression — implementations have bugs, particularly IE.)
In contrast, this is a function declaration:
function bar() { ... }
It's stand-alone, you're not using the result as a right-hand value.
The two main differences between them:
Function expressions are evaluated where they're encountered in the program flow. Declarations are evaluated when control enters the containing scope (e.g., the containing function, or the global scope).
The name of the function (if it has one) is defined in the containing scope for a function declaration. It is not for a function expression (barring browser bugs).
Your anonymous functions are function expressions, and so barring the interpreter doing optimization (which it's free to do), they'll get recreated on each loop. So your use is fine if you think implementations will optimize, but breaking it out into a named function has other benefits and — importantly — doesn't cost you anything. Also, see casablanca's answer for a note about why the interpreter may not be able to optimize out recreating the function on each iteration, depending on how deeply it inspects your code.
The bigger issue would be if you used a function declaration in a loop, the body of a conditional, etc.:
function foo() {
for (i = 0; i < limit; ++i) {
function bar() { ... } // <== Don't do this
bar();
}
}
Technically, a close read of the spec's grammar shows it's invalid to do that, although virtually no implementation actually enforces that. What the implemenations do is varied and it's best to stay away from it.
For my money, your best bet is to use a single function declaration, like this:
function foo() {
for (i = 0; i < limit; ++i) {
bar();
}
function bar() {
/* ...do something, possibly using 'i'... */
}
}
You get the same result, there's no possibility that an implementation will create a new function on every loop, you get the benefit of the function having a name, and you don't lose anything.
Would a Javascript interpreter really create an instance of the function per iteration?
It has to because it doesn't know if the function object will be modified elsewhere. Remember that functions are standard JavaScript objects, so they can have properties like any other object. When you do this:
card = $('<div>').bind('isPopulated', function (ev) { ... })
for all you know, bind
could modify the object, for example:
function bind(str, fn) {
fn.foo = str;
}
Clearly this would result in wrong behaviour if the function object was shared across all iterations.