Let’s take a look at this code. This is a famous example when understanding closures.


function buildFuncs() {
    var arr = [];
    for (var i = 0;i < 3;i++) {
        arr.push(
            function() {
                console.log(i);
            }
        )
    }

    return arr;
}

var funcs = buildFuncs();

funcs[0](); // outputs 3
funcs[1](); // outputs 3
funcs[2](); // outputs 3

Without looking at the output, it is natural to assume outputs to be 0, 1, 2, but it ouputs 3 altogether, because of the closure.

The execution context of buildFuncs will have a variable i, and the array will have 3 anonymous functions. After buildFuncs have finished, the execution context will be removed from the execution stack but the memory of i would be still there i = 3.

To fix this to output 1, 2, 3, we can do the following.


function buildFuncs() {
    var arr = [];
    for (var i = 0;i < 3;i++) {
        arr.push(
            function(i) {
                console.log(i);
            }
        )
    }

    return arr;
}

var funcs = buildFuncs();

funcs[0](0); // outputs 0
funcs[1](1); // outputs 1
funcs[2](2); // outputs 2

But this case we have to pass in the parameter to get it! Can we do it without passing the parameters?

In ES6, the let variable is a variable that lives in the context of a block, so inside the for loop it will make a new let every time.


function buildFuncs() {
    var arr = [];
    for (var i = 0;i < 3;i++) {
        let j = i;
        arr.push(
            function() {
                console.log(j);
            }
        )
    }

    return arr;
}

var funcs = buildFuncs();

funcs[0](); // outputs 0
funcs[1](); // outputs 1
funcs[2](); // outputs 2

This will work.

Without let, we can use IIFE(Immediately invoked Function Expressions) IIFEs actually execute the function immediately thus they make the execution contexts each, which will have a memory space for is individually. In this case, j.


function buildFuncs() {
    var arr = [];
    for (var i = 0;i < 3;i++) {
        arr.push(
            (function(j) {
                return function() {
                    console.log(j);
                }
            }(i))
        )
    }

    return arr;
}

var funcs = buildFuncs();

funcs[0](); // outputs 0
funcs[1](); // outputs 1
funcs[2](); // outputs 2