Scheintod
Scheintod

Reputation: 8105

JS: Which / How are variables stored in closures?

Consider following code:

    var a = [ { a: 'I' }, { a: 'II' }, { a: 'III' } ];

    for( var i=0; i<a.length; i++ ){

            var j = i;
            var x = a[ i ];

            x.bb = function(){
                    x.b = "-" + x.a + "-";
            }
            x.cc = function(){
                    a[ i ].c = "-" + a[ i ].a + "-";
            }
            x.dd = function(){
                    a[ j ].d = "-" + a[ j ].a + "-";
            }
    }

    for( var i=0; i<a.length; i++ ){
            a[i].bb();
            a[i].cc();
            a[i].dd();
    }

    console.log( a );

will result in (functions left out):

[ { a: 'I', c: '-I-' },
  { a: 'II', c: '-II-' },
  { a: 'III', b: '-III-', d: '-III-', c: '-III-' } ]

So only cc() does what I intended to do.

My question now is:

  1. What are the rules here how the variables are stored in the closure. (Obviously i is stored as a constant while j and x are stored as reference to the local variables which are changed while the for-loop iterates. But why is that?) There was my mistake. The code did only work because the second and the first i where the same!
  2. Is there a way to write bb() in a way that it stores a reference to a[ i ] so that I don't have to use the index?

Thanks!

Upvotes: 0

Views: 451

Answers (1)

Jordan Kasper
Jordan Kasper

Reputation: 13273

You need to keep in mind that JavaScript does not have block scoping (well, not yet anyway, ES6 is working that in with let), instead, everything is at the "function" level. That is, all variables are scoped to their most recent function definition.

Variables are declared using the var statement, and according to your code, every variable you have is scoped to the outer container for this code. In other words, if this code is in a Node module, then all of the variables in here are scoped to the entire module. As such, although your functions defined inside the for loop are closures (because all JS functions are closures), they are still just using the variables defined within the module at large since there is no need for JS to look any further.

To illustrate this answer to question 1, consider the following:

var o = {};
var x = 1;

function foo() {
    var x = 2;
    o.bar = function() {
        console.log(x);
    }
}

o.bar(); // will output "2" because of the closure created in `foo()`

As for your second question, because a[i] is an object, any variable you assign that object to (in this case, x) will be a reference, and all references will point to the same object in memory. I'm not what you're trying to accomplish with bb(), but you are "storing a reference to a[ i ]" by using x. Perhaps you have a more specific example?

Upvotes: 2

Related Questions