Search code examples
javascriptclosuresmutable

JS closure for mutable variables


Please help me find the reason why the local "j" variable continues to change during the loop:

var a1 = a2 = a3 = {};

for (var i = 1; i < 4; i ++ ) {
  (function(j){
    console.log(j);
    window['a'+j].fu = function(){
      console.log('fu:',j);
    };
  })(i);

}

a1.fu(); // returns "fu:,3" - why not 1?

a2.fu(); // returns "fu:,3" - why not 2?

a3.fu(); // returns "fu:,3"

I read the nice answer on similar issue, but it's not working for my case. Mutable variable is accessible from closure. How can I fix this?


Solution

  • Object assignment does not make copy of the objects, the same object is referenced by all the three variables. So, even changing the value inside the loop will update the same location for different object.

    The value in the object is set as 3 in the last iteration of the loop and when retrieving the value after for loop, the value 3 is returned for all the variables.

    When you create objects

    var a1 = a2 = a3 = {};
    

    all the three variables refer to the same object.

    Solution to the problem can be declaring the object individually.

    var a1 = {},
        a2 = {},
        a3 = {};
    
    for (var i = 1; i < 4; i++) {
      (function(j) {
        console.log(j);
        window['a' + j].fu = function() {
          console.log('fu:', j);
        };
      })(i);
    }
    
    a1.fu(); // returns "fu:,3" - why not 1?
    
    a2.fu(); // returns "fu:,3" - why not 2?
    
    a3.fu(); // returns "fu:,3"