Search code examples
javascriptscopeclosuresiife

IIFEs as closures


In the You Don't Know Javascript series, 1/3 of the way down IIFE's are described as not being closures themselves, but only if they're executed outside their lexical scope:

Chapter 3 introduced the IIFE pattern. While it is often said that IIFE (alone) is an example of observed closure, I would somewhat disagree, by our definition above.

This code "works", but it's not strictly an observation of closure. Why? Because the function (which we named "IIFE" here) is not executed outside its lexical scope. It's still invoked right there in the same scope as it was declared (the enclosing/global scope that also holds a). a is found via normal lexical scope look-up, not really via closure.

var a = 2;

(function IIFE(){ // not actually a "closure"
    console.log( a ); 
})();

In this SO post, the following snippet was given as an example of a closure:

for (var i = 0; i < someVar.length; i++)
    (function (i) {
        window.setTimeout(function () { 
            alert("Value of i was "+i+" when this timer was set" )
        }, 10000);
    })(i); 

I am trying to understand this in terms of the definition of closure (as defined in this medium article):

To use a closure, simply define a function inside another function and expose it. To expose a function, return it or pass it to another function. ...

The inner function will have access to the variables in the outer function scope, even after the outer function has returned.

I understand that a closure is a "stateful function", and that it is

a way to "remember" and continue to access a function's scope (its variables) even once the function has finished running.

So in this example, I see that the loop's i is remembered when passed into the closing IIFE.

My question is:

Where is the "passing to another function or returning" portion happening? My guess is that the IIFE is able to remember the outer i for loop value at each iteration because the IIFE is passed to the window?

Basically, my understanding is that a closure is defined as remembering an outer scope's value after the Garbage collector cleans that outer scope up, and that the usage of it is to expose the closure by returning it and accessing it outside its lexical scope. Is this correct? So where is that "accessing it outside the lexical scope" happening?


Solution

  • in this example, I see that the loop's i is remembered when passed into the closing IIFE

    No. The IIFE is only providing the scope for the i value to be remembered. As the quotes you cited state, the IIFE function is not a closure. The function expression that uses the i is the closure:

    (function IIFE(i) {
        // this is the scope of i
    
        window.setTimeout(function closure() {
            // this function closes over i
            alert("Value of my local 'i' is still "+i+" even after 10 seconds");
        }, 10000);
    })(0);
    // ^ this is some arbitrary value passed to the IIFE - it could have been a loop variable
    

    Where is the "passing to another function or returning" portion happening?

    It's the closure function being passed into setTimeout, which will call it back from a place where i would usually be no longer defined - if it wasn't a closure.