The problem in this case has to do with scoping in JS.
Since there is no block scope, it's basically equivalent to
this.setMember = function() {
var self = this;
var index;
for(; this.counter < 10; this.counter++){
index = this.counter;
setTimeout(function(){
self.arr[index] = 'I am John!';
}, 100);
}
};
Of course, since the assignment is asynchronous, the loop will run to completion, setting index to 9. Then the function will execute 10 times after 100ms.
There are several ways you can do this:
IIFE (Immediately invoked function expression) + closure
this.setMember = function() {
var self = this;
var index;
for(; this.counter < 10; this.counter++){
index = this.counter;
setTimeout((function (i) {
return function(){
self.arr[i] = 'I am John!';
}
})(index), 100);
}
};
Here we create an anonymous function, immediately call it with the index, which then returns a function which will do the assignment. The current value of index is saved as i in the closure scope and the assignment is correct
Similar to 1 but using a separate method
this.createAssignmentCallback = function (index) {
var self = this;
return function () {
self.arr[index] = 'I am John!';
};
};
this.setMember = function() {
var self = this;
var index;
for(; this.counter < 10; this.counter++){
index = this.counter;
setTimeout(this.createAssignmentCallback(index), 100);
}
};
Using Function.prototype.bind
this.setMember = function() {
for(; this.counter < 10; this.counter++){
setTimeout(function(i){
this.arr[i] = 'I am John!';
}.bind(this, this.counter), 100);
}
};
Since all we care about is getting the right kind of i into the function, we can make use of the second argument of bind, which partially applies a function to make sure it will be called with the current index later. We can also get rid of the self = this line since we can directly bind the this value of the function called. We can of course also get rid of the index variable and use this.counter directly, making it even more concise.
Personally I think the third solution is the best.
It's short, elegant, and does exactly what we need.
Everything else is more a hack to accomplish things the language did not support at the time.
Since we have bind, there is no better way to solve this.