DEV Community

Hihi
Hihi

Posted on • Edited on

Scope & Closure in Javascript - Army of functions challenge

While researching about scope and closure, I came across this challenge from javascrip.info, The question is shown below:

function makeArmy() {

    let shooters = [];
    let i = 0;

    while (i < 10) {
        let shooter = function() { // create a shooter function,
            alert( i ); // that should show its number
        };
        shooters.push(shooter); // and add it to the array
        i++;
    }
    return shooters;
}
let army = makeArmy();

// all shooters show 10 instead of their numbers 0, 1, 2, 3...
army[0](); // 10 from the shooter number 0
army[1](); // 10 from the shooter number 1
army[2](); // 10 ...and so on.
Enter fullscreen mode Exit fullscreen mode

So, what is really happening?

As we can see, each iteration of the while loop we initialized and assigned the shooter function and then store them in the shooters array. Each instance has the reference to the i variable.

Let's dive in the action of function.

When we invoke army[0](), it firstly search the i variable in its local memory (which is the function's inner scope). When it cannot find i in its local scope, it continues to populate to the outside scope and searching for i, the current scope is now in the while loop (inner the {...}). In this scope there's still not any i. It continues to search in the broader scope, which is the makeArmy 's environment, now there's one i holding the value of 10, and yet the 10 is logged in the alert(i) function.

Image description

How to make the i unique value as we wanted?

Simply we will create a copied local variable of i in the iteration scope (while loop's scope)

function makeArmy() {

    let shooters = [];
    let i = 0;

    while (i < 10) {
        let j = i; ๐Ÿ‘ˆ
        let shooter = function() { 
            alert( j ); ๐Ÿ‘ˆ
        };
        shooters.push(shooter);
        i++;
    }
    return shooters;
}
Enter fullscreen mode Exit fullscreen mode

The j is now living in the iteration scope and each iteration it holds a new value of i incremented. And each instance of shooter has its own unique j but not using the outer i

Image description

j is encapsulated in each instance of shooter.

Conclusion:

  • Be careful when using the shared variable between instances of function.
  • Each block scope has it own scope
{
  let scopedContent = 'Hello scope'
}

console.log(scopedContent) 
// ReferenceError: scopedContent is not defined
Enter fullscreen mode Exit fullscreen mode

Top comments (0)