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:

  1. 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).

  2. 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.

Leave a Comment

tech