Scope and IIFE in JS

Asked

Viewed 144 times

3

Are you guys okay? I am here with a question in a small code, basically I have a for loop that add an event click to each number where will be shown the number that was clicked in Alert, and of course the number shown is always the last, So far I have noticed, but I’m having a hard time understanding the Scope that was added to the code, I understand that in the Inner-Scope we have access to variable Outer-Scope but not the other way around, but I still don’t understand the technique that is applied here, I hope you can help me understand:

var nums = [1,2,3];

for (var i = 0; i < nums.length; i++) {
var num = nums[i];
elem.addEventListener('click', (function(numCopy) {
    return function() {
        alert(numCopy)
    };
})(num));

}

1 answer

3

I’ll try to explain what’s going on in the code. The first point worth noting is the "Declaration Hoisting": https://developer.mozilla.org/en-US/docs/Glossary/Hoisting Which means the elevation of variable declarations to the top of the scope, which can be global or function. That is to say:

for(var i=0; i < nums.length; i++)

It’s like doing:

var i;
for(i = 0; i < nums.length; i++)

This way the variable i will be available for use by everyone within the scope.

And for this reason that by adding a click this way:

elem.addEventListener('click', function() {
        alert(nums[i])
});

It will always result in the last number being displayed. Because the anonymous function you created has access to variables i and nums that were in the same scope as the anonymous function. Meaning that at the moment the function is executed the variable i contains the index of the last element of the Array.

IIFE

To mitigate this problem, we use an IIFE (Immediately Invoked Function Expression), a function that is executed immediately upon being created. Usually expressed in this way:

(function(){

}())

Or

(function(){

})()

Although I personally prefer the first option. By doing what you demonstrate in the code, the following happens:

  1. IFFE shall be implemented during the loop and takes as parameter the value contained in the current index of the Array;

    elem.addEventListener('click', (function(num) {
    
    })(nums[i]));
    
  2. As a new function has been declared, a new scope is created. This scope has a variable called in a that contains the value contained in the index of the array with which the function was called.

  3. You return a new function that when executed will call the function Alert, passing one as parameter;

    return function() {
      alert(num);
    };
    
  4. This new function, which was created in the clause Return is then added as event manager;

    elem.addEventListener('click', (function(num) {
       return function() {
         alert(num)
       };
    })(nums[i]));
    

In your case, when clicking always displays the last number of the Array because, from what I understand, you call the addeventlistener several times in the same element. Thus, when adding a new Istener, the old one is overwritten.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.