Closures in JavaScript

Posted on by By Nikhilesh, in Front End, Javascript | 0

In this post, we mainly focus on Closures in a loop.

Sometimes it will be hard-to-spot bugs when it comes to Closures because everything looks great on the surface. For example, let us consider this function:

function F() {
    var arr = [], i;
    for (i = 0; i < 3; i += 1) {
        arr[i] = function () {
            return i;
        };
    }
    return arr;
}

In the above example, we are looping three times, each time creating a new function that returns the loop sequence number. The new functions will be added to an array and the array is returned at the end. So, let’s the run code..

> var arr = F();

Now you have an array of three functions and let’s invoke them by adding parentheses after each array element. The expected behavior is to see the loop sequence printed: 0, 1, 2. Let’s try:

> arr[0]();
3
> arr[1]();
3
> arr[2]();
3

We didn’t expect this result. Did we? So, what has happened there? All three functions pointed to the same local variable i. Why? The functions don’t remember values, they only keep a link (reference) to the environment variable where they were created. In this case, the variable i happens to live in the environment where the three functions were defined. So, all the functions, when they need to access the value, reach back to the environment and find the most current value of i. After the loop, the i variable’s value is 3. So, all the three functions point to the same value.

Why three and not two is another good question to think about for better understanding the for loop.

So, how do you implement the correct behavior? The answer is to use another Closure:

function F() {
    var arr = [], i;
    for (i = 0; i < 3; i += 1) {
        arr[i] = (function (x) {
            return function () {
                return x;
            };
        }(i));
    }
    return arr;
}

And this gives you the expected result.

> var arr = F();

> arr[0]();
0

> arr[1]();
1

> arr[2]();
2

Here, instead of creating a function that returns i, you pass the i variable’s current value to another immediate function. In this function, i becomes the local value of x, and x has different value every time.

Alternatively, you can use a normal (as opposed to an immediate) inner function to achieve the same result. The key is to use the middle function to localize the value of i at every iteration.

function F() {
    function binder(x) {
        return function () {
            return x;
        };
    }
    
    var arr = [], i;
    for (i = 0; i < 3; i += 1) {
        arr[i] = binder(i);
    }
    return arr;
}

So, when dealing the Closures in a loop, it is better to understand what’s running internally rather than focusing on the surface code.

-By
Uma Maheswar
Helical It Solution

logo

Best Open Source Business Intelligence Software Helical Insight is Here

logo

A Business Intelligence Framework

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments