Search code examples
javascriptclosuresiife

IIFE: Why does my code ignore an addEventListener if I return an alert without wrapping it in a function?


I'm perplexed as to why I have to wrap my alert in a function in order to avoid my code ignoring the event listener.

If I run this code, It'll work properly and I'll be able to click and have the alert display after the click

    elem.addEventListener('click', (function(numCopy) {
    return function() {
        alert(numCopy);
    };
})(num));

But if I run this code, it'll ignore the event listener and display the alert as soon as the page loads

elem.addEventListener('click', (function(numCopy) {
return alert(numCopy);
})(num));

I could ignore it and just accept this is the way it's done but I would really appreciate it if someone could explain the logic behind this so I can fully grasp the concept, thanks a lot in advance.


Solution

  • Lets figure out what's going on by looking at the following example:

    function foo(x) {
      return x;
    }
    
    var bar = foo(42);
    baz(bar);
    

    What is the value passed to baz? 42 because foo simply returns the value passed to it.

    Now lets inline the function call:

    function foo(x) {
      return x;
    }
    
    baz(foo(42));
    

    What is the value passed to baz here? Still 42 whether we assign the return value to a variable or directly pass it to the other function doesn't make a difference.

    Now lets inline the function definition:

    baz(function foo(x) { return x; }(42));
    

    Now we have an IIFE. What is the value passed to baz here? Still 42. We didn't actually change what the code is doing, we just got rid of intermediate variable assignments (we could also drop foo from the function expression).


    How does this related to your code? Lets work our way backwards from your code. We start with:

    elem.addEventListener('click', (function(numCopy) {
       return alert(numCopy);
    })(num));
    

    Lets extract the function definition:

    function foo(numCopy) {
      return alert(numCopy);
    }
    
    elem.addEventListener('click', foo(num));
    

    Now lets extract the function call:

    function foo(numCopy) {
      return alert(numCopy);
    }
    
    var bar = foo(num);
    elem.addEventListener('click', bar);
    

    Do you see what's wrong here? You are calling the function (foo in this case). The function executes alert and that's why you immediately see the alert.

    foo returns the return value of alert (assigned to bar), so you are passing that value to addEventListener.

    But alert returns undefined whereas addEventListener expects to be passed a function.

    That's why your IIFE needs to return a function.