Rectangle 27 0

javascript How to fix jslint error 'Don't make functions within a loop.'?


.jshintrc
{"loopfunc" : true,      // tolerate functions being defined in loops }
  • Create a .jshintrc file

Literally, get around the problem by doing the following:

Note
Rectangle 27 0

javascript How to fix jslint error 'Don't make functions within a loop.'?


handler = function (div_id) {
    return function() { alert(div_id); }
}

for (i ...) {
    div_id = divs[i].id;
    divs[i].onclick = handler(div_id);
}

(I just stumbled on this questions many months after it was posted...)

+1 but I consider this a false-positive when the function actually uses different variables per loop iteration. Using a "function maker" is no better than instantiating it inside the loop.

As for JSLint: Yes, it is dogmatic and idiomatic. That said, it is usually "right" -- I discover that many many people who vocalize negatively about JSLint actually don't understand (the subtleties of) Javascript, which are many and obtuse.

If the function is actually the same function being assigned to different values in an iteration (or objects produced in an iteration), then instead you need to assign the function to a named variable, and use that singular instance of the function in assignment within the loop:

If you make a function in a loop, an instance of a function is created for each iteration of the loop. Unless the function that is being made is in fact different for each iteration, then use the method of putting the function generator outside the loop -- doing so isn't just Crockery, it lets others who read your code know that this was your intent.

While there are no vars declared, this is pseudo-code...also when you invoke handler(div_id); it returns a function, it will not run the alert until clicked in this example. Here is a full example: jsfiddle.net/scottux/RWCje

please add vars for the variables (handler, div_id).

when you invoke handler(div_id) you actually run the function which will show the alert. This will happen when the for runs and not when the user clicks on the div.

Note
Rectangle 27 0

javascript How to fix jslint error 'Don't make functions within a loop.'?


function make_handler(div_id) {
    return function () {
        alert(div_id);
    };
}
for (i ...) {
    div_id = divs[i].id;
    divs[i].onclick = make_handler(div_id);
}

@AshClarke It is correct that make_handler is not recreated for each iteration of the loop but it remains that for each iteration of the loop the value returned by make_handler is a new function object. What the code in this answer does is just hide from a code checker that a new function is created with each iteration but does not prevent the creation of a new function with each iteration. Compare the return values of multiple calls to make_handler with === and see for yourself.

@Gili: The code to create the make_handler function is executed at the point it says function make_handler(div_id). Once inside the for loop, make_handler is now a reference to that function and is not being re-created for every iteration of the loop.

@Louis Yes, true; I should have been more explicit. I was indeed trying to get across that the creation of the make_handler function was not evaluated over and over, but that is a good point I should have made about the return value.

Douglas Crockford has a new idiomatic way of achieving the above - his old technique was to use an inner function to bind the variables, but the new technique uses a function maker. See slide 74 in the slides to his "Function the Ultimate" talk. [This slideshare no longer exists]

For the lazy, here is the code:

How is a "function maker" any better than creating a new function per loop iteration? Isn't it the same thing?

The function maker is better because it will actually work properly. See stackoverflow.com/questions/750486/

Note
Rectangle 27 0

javascript How to fix jslint error 'Don't make functions within a loop.'?


function make_handler(div_id) {
    return function () {
        alert(div_id);
    };
}
for (i ...) {
    div_id = divs[i].id;
    divs[i].onclick = make_handler(div_id);
}

@AshClarke It is correct that make_handler is not recreated for each iteration of the loop but it remains that for each iteration of the loop the value returned by make_handler is a new function object. What the code in this answer does is just hide from a code checker that a new function is created with each iteration but does not prevent the creation of a new function with each iteration. Compare the return values of multiple calls to make_handler with === and see for yourself.

@Gili: The code to create the make_handler function is executed at the point it says function make_handler(div_id). Once inside the for loop, make_handler is now a reference to that function and is not being re-created for every iteration of the loop.

@Louis Yes, true; I should have been more explicit. I was indeed trying to get across that the creation of the make_handler function was not evaluated over and over, but that is a good point I should have made about the return value.

Douglas Crockford has a new idiomatic way of achieving the above - his old technique was to use an inner function to bind the variables, but the new technique uses a function maker. See slide 74 in the slides to his "Function the Ultimate" talk. [This slideshare no longer exists]

For the lazy, here is the code:

How is a "function maker" any better than creating a new function per loop iteration? Isn't it the same thing?

The function maker is better because it will actually work properly. See stackoverflow.com/questions/750486/

Note
Rectangle 27 0

javascript How to fix jslint error 'Don't make functions within a loop.'?


handler = function (div_id) {
    return function() { alert(div_id); }
}

for (i ...) {
    div_id = divs[i].id;
    divs[i].onclick = handler(div_id);
}

(I just stumbled on this questions many months after it was posted...)

+1 but I consider this a false-positive when the function actually uses different variables per loop iteration. Using a "function maker" is no better than instantiating it inside the loop.

As for JSLint: Yes, it is dogmatic and idiomatic. That said, it is usually "right" -- I discover that many many people who vocalize negatively about JSLint actually don't understand (the subtleties of) Javascript, which are many and obtuse.

If the function is actually the same function being assigned to different values in an iteration (or objects produced in an iteration), then instead you need to assign the function to a named variable, and use that singular instance of the function in assignment within the loop:

If you make a function in a loop, an instance of a function is created for each iteration of the loop. Unless the function that is being made is in fact different for each iteration, then use the method of putting the function generator outside the loop -- doing so isn't just Crockery, it lets others who read your code know that this was your intent.

While there are no vars declared, this is pseudo-code...also when you invoke handler(div_id); it returns a function, it will not run the alert until clicked in this example. Here is a full example: jsfiddle.net/scottux/RWCje

please add vars for the variables (handler, div_id).

when you invoke handler(div_id) you actually run the function which will show the alert. This will happen when the for runs and not when the user clicks on the div.

Note
Rectangle 27 0

javascript How to fix jslint error 'Don't make functions within a loop.'?


function make_handler(div_id) {
    return function () {
        alert(div_id);
    };
}
for (i ...) {
    div_id = divs[i].id;
    divs[i].onclick = make_handler(div_id);
}

@AshClarke It is correct that make_handler is not recreated for each iteration of the loop but it remains that for each iteration of the loop the value returned by make_handler is a new function object. What the code in this answer does is just hide from a code checker that a new function is created with each iteration but does not prevent the creation of a new function with each iteration. Compare the return values of multiple calls to make_handler with === and see for yourself.

@Gili: The code to create the make_handler function is executed at the point it says function make_handler(div_id). Once inside the for loop, make_handler is now a reference to that function and is not being re-created for every iteration of the loop.

@Louis Yes, true; I should have been more explicit. I was indeed trying to get across that the creation of the make_handler function was not evaluated over and over, but that is a good point I should have made about the return value.

Douglas Crockford has a new idiomatic way of achieving the above - his old technique was to use an inner function to bind the variables, but the new technique uses a function maker. See slide 74 in the slides to his "Function the Ultimate" talk. [This slideshare no longer exists]

For the lazy, here is the code:

How is a "function maker" any better than creating a new function per loop iteration? Isn't it the same thing?

The function maker is better because it will actually work properly. See stackoverflow.com/questions/750486/

Note
Rectangle 27 0

javascript How to fix jslint error 'Don't make functions within a loop.'?


.click()
for (var i = 0; i < 100; i++) {
  $("#button").click(function() {
    alert(i);
  });
}
function new_function(e) {
  var data = e.data; // from handler
  alert(data); // do whatever
}

for (var i = 0; i < 100; i++) {
  $("#button").click(i, new_function);
}

If you are using JQuery, you might want to do something like this in a loop:

Note
Rectangle 27 0

javascript How to fix jslint error 'Don't make functions within a loop.'?


.jshintrc
{"loopfunc" : true,      // tolerate functions being defined in loops }
  • Create a .jshintrc file

Literally, get around the problem by doing the following:

Note
Rectangle 27 0

javascript How to fix jslint error 'Don't make functions within a loop.'?


.click()
for (var i = 0; i < 100; i++) {
  $("#button").click(function() {
    alert(i);
  });
}
function new_function(e) {
  var data = e.data; // from handler
  alert(data); // do whatever
}

for (var i = 0; i < 100; i++) {
  $("#button").click(i, new_function);
}

If you are using JQuery, you might want to do something like this in a loop:

Note
Rectangle 27 0

javascript How to fix jslint error 'Don't make functions within a loop.'?


I know that jslint is only a recomendation and that it's intended to be used to spot bad JS code, but it's still a good tool to use to pre-qualify and sanity check your code in an automated build/test environment. As I wrote, I'm interested in workarounds to make the code pass jslint, not avoid running jslint at all.

JSLint is only a guide, you don't always have to adhere to the rules. The thing is, you're not creating functions in a loop in the sense that it's referring to. You only create your classes once in your application, not over and over again.

Maybe this is covered by someone else in this discussion but I don't see it: I feel like the proposed solution is better with the implication that you're binding a function in a loop, not creating it. Technically, you are (obviously), but it was my understanding that JSLint gives you this hint because functions are supposed to be available at runtime, before the iterator or limit of a loop is defined. In this case, if the iterator results in 0 iterations of the loop, the function is still declared but not bound. As far as how javascript actually interprets this, I'm assuming that part is moot.

Of course, those solutions are obvious. The point remains, you're still creating functions inside the loop, you've just written it in a particular way that is arguably more convoluted, just to appease some tool. Whatever, if that's what you want to do, go for it.

Sure, but if you look at the answer below, you're still making a function in a loop. You're adding extra code just to appease JSLint. Why would you do this?

Yes I still make functions within a loop, my problem was that I wanted this code to pass jslint. Now Skilldrick and Matt Eberts gave me working solutions which I have tested and now my code both works and passes jslint. I am an old C/C++ programmer, I'm used to have syntax checking as part of the compilation stage. Javascript lacks compilation, jslint is as close as you get to using a modern c/c++ compiler with warnings.

Note