4

Possible Duplicate:
Javascript closure inside loops - simple practical example

I'm trying to use a self invoking function so that each function in objects will return a different message.

<script type="text/javascript">

    objects = {};

    for( var i = 0; i < 10; i++ ) {

        objects['function'+i] = function () {

            var text = ( function() { return "I am object " + i; } )();

            return text;

        };

    }

    for( var j = 0; j < 10; j++ ) {

        document.write( objects['function'+j]() + "<br>" );

    }

</script>

So far the above results in:

I am object 10

I am object 10

I am object 10

I am object 10

I am object 10

I am object 10

I am object 10

I am object 10

I am object 10

I am object 10

How can I use self invoking-functions to set the message immediately and not be tied to the precarious i?

Community
  • 1
  • 1
Joncom
  • 1,985
  • 1
  • 18
  • 29

4 Answers4

8

You need to pass in the iterator variable so your anonymous function can store that in its own activation object / lexical environment record ( = in its very own context object ).

Furthermore, you need this anonymous function to wrap all access points:

objects[ 'function' + i ] = function( i ) {

    var text = function() { return "I am object " + i; };

    return text;

}( i );
jAndy
  • 231,737
  • 57
  • 305
  • 359
1

You need to build a closure, closing over that particular i variable and returning the function that is untied from i:

for (var i = 0; i < 10; i++) {
    objects['function'+i] = ( function (num) {
        return function() {
            var text = "I am object " + num;
            return text;
        };
    } )( i ); // <== put the variable into the self-invoking function
}
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    I'm always a bit picky in this regard: The function the OP uses is already a closure. You introduced a new context using a self-invoking function but that does not have to be a closure. The function returned by the self-invoking must be a closure though (maybe that's what you referred to anyways... just wanted to clarify it). – Felix Kling Dec 20 '12 at 00:17
  • Does he? I thought the function that returns the other function (in here my IEFE) is the closure, not the returned function. – Bergi Dec 20 '12 at 00:30
  • @Bergi—it's the closure involving `i` that is the issue. The OP needs to avoid it, not "build" it. – RobG Dec 20 '12 at 00:42
  • I don't see any closures in the OPs code. He has a function, and inside it he uses a superfluous IEFE. – Bergi Dec 20 '12 at 00:44
  • 1
    The function that is assigned to `objects['function'+i]` is a closure... it has access to the variable `i`, i.e. it *closes* over `i`. Technically, *every* function in JavaScript is a closure since they always have access to the variables defined in a higher scope. The solution to closures in a loop is that a new scope is created. – Felix Kling Dec 20 '12 at 02:08
  • Right, I missed that one as it doesn't leave the scope it was defined in. Technically, you're correct. – Bergi Dec 20 '12 at 02:43
0

You need a closure.. see King Resig's explanation here http://ejohn.org/apps/learn/#59 for an explanation. But for this code to work you would have to ensure that the value of i is maintained when the function is called... so it would be something like

http://jsbin.com/uveluw/1/edit

for( var i = 0; i < 10; i++ ) (function(i){

    objects['function'+i] = function () {
        var text = ( function() { return "I am object " + i; } )();
        return text;
    };

})(i)
Justin Bicknell
  • 4,804
  • 18
  • 26
  • `You need a closure`—oops, quite the opposite. The OP needs to avoid the closure. – RobG Dec 20 '12 at 00:37
  • No I'm pretty sure what we are doing is building a closure to encapsulate i, so that the outer loop no longer has that variable in scope... see https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Closures – Justin Bicknell Dec 20 '12 at 18:27
  • The outer i is always "in scope" and always exists in a closure, assigning the value to a local variable means that the local variable is used, not i (noting that you can use the same name for a local variable and get the same effect). – RobG Dec 21 '12 at 00:05
0

Immediately execute the return value so that i is closed over the loop:

objects = {};
for( var i = 0; i < 10; i++ ) {
    objects['function'+i] = (function () {
        var text = ( function() { return "I am object " + i; } )();
        return text;
    })();
}

for( var j = 0; j < 10; j++ ) {
    console.log( objects['function'+j] );
}
Travis J
  • 81,153
  • 41
  • 202
  • 273