-1

I have a loop that adds a function to an object for each iteration. These functions are called later to change the innerHTML of several elements. The problem I am running into is that the values returned by the function calls are not what I expect. The results that I expect are shown as comments next to each function call below. Any help would be appreciated.

var set = [1, 2, 3];
var obj = {};
for (var i = 0; i < set.length; i++) {
  obj['obj' + i] = {
    func: function() {
      return ['test', i].join('');
    }
  }
}

document.getElementById("obj0").innerHTML = obj.obj0.func(); // test1
document.getElementById("obj1").innerHTML = obj.obj1.func(); // test2
document.getElementById("obj2").innerHTML = obj.obj2.func(); // test3
<div id='obj0'></div>
<div id='obj1'></div>
<div id='obj2'></div>
coderfin
  • 1,708
  • 19
  • 24
Ton
  • 73
  • 2
  • 7

2 Answers2

1

This is a common problem that can be solved with Closures. The value of i is the final value of i at the time of the function calls not at the time of the function creation. Using closure will help ensure that you are using the value of i at creation time instead of call time.

var set = [1, 2, 3];
var obj = {};
for (var i = 0; i < set.length; i++) {
    obj['obj' + i] = {
        func: (function (i) {
            return function() {
                return ['test', i + 1].join('');
            };
        })(i)
    }
}

document.getElementById("obj0").innerHTML = obj.obj0.func(); // test1
document.getElementById("obj1").innerHTML = obj.obj1.func(); // test2
document.getElementById("obj2").innerHTML = obj.obj2.func(); // test3
<div id='obj0'></div>
<div id='obj1'></div>
<div id='obj2'></div>
coderfin
  • 1,708
  • 19
  • 24
0

You can use bind:

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

var set = [1, 2, 3];
var obj = {};

function func(i) {
  return ['test', i].join('');
}

for (var i = 0; i < set.length; i++) {
  obj['obj' + i] = {
    func: func.bind(null, set[i])
  }
}

document.getElementById("obj0").innerHTML = obj.obj0.func(); // test1
document.getElementById("obj1").innerHTML = obj.obj1.func(); // test2
document.getElementById("obj2").innerHTML = obj.obj2.func(); // test3
<div id='obj0'></div>
<div id='obj1'></div>
<div id='obj2'></div>
CD..
  • 72,281
  • 25
  • 154
  • 163