0

I am stuck on this code:

this.unwatches[id] = [];
            for (let i: number = 0; i < this.columns.length; i++ ) {
                this.unwatches[id].push($scope.$watch((): any => {
                    return entity[this.columns[i].attribute];
                }, (newValue: any): void => {
                    this.grid.cells(id, i).setValue(newValue);
                }));
            }

and I got this error:

Loop contains block scoped variable 'i' referenced by a function in the loop.

I found this thread: Typescript - closure inside loop

which is exactly my problem, but I got trouble adapt my code. Anyone could help me?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Kalimero95
  • 43
  • 1
  • 9

2 Answers2

2

All you need to do is to capture the value of i using an immediately invoked function expression, which effectively creates a closure for i. For example:

for (let i: number = 0; i < this.columns.length; i++) {
    ((i) => {
        // this.unwatches[id].push ...
    })(i);
}

This will create a new i inside the closure, which is not the same i as the one used in the loop, and remains unchanged until the inner scope of the closure is garbage collected. In other words, the "outer" i is shadowed by the "inner" i -- that is, the inner one cannot be changed from the outside, e.g. by incrementing the loop counter, because they refer to two different objects.

Note, that an anonymous function object is created for every iteration in your loop, which might have an effect on performance when you are doing massive loops.

John Weisz
  • 30,137
  • 13
  • 89
  • 132
0

You need to use var with IIFE (Immediately Invoked Function Expression) to capture i at each iteration. To implement IIFE you just need to wrap your function as following:

(function(i) {
        //your function goes here
    })(i);
RafaelJan
  • 3,118
  • 1
  • 28
  • 46
  • You can still use a `let`, but indeed, the solution is to use an IIFE. – John Weisz Feb 28 '17 at 13:17
  • Yes, `let` is ok, it just passes the i variable for the lambda function. In this case lambda function uses same name for the argument which is also ok. – Antti Feb 28 '17 at 13:26