Search code examples
javascriptiife

From where is an IIFE actually invoked?


Looking at an example of a simple IIFE

((x) => x)(1) // returns 1

If I were to think of this in terms of a regular (but anonymous) function that could be passed as a callback:

setTimeout(function() {alert(1)}, 1000)

The anonymous function is still being invoked. The IIFE similarly looks like it is passed as a callback to some function that returns a function.

It looks like this returned function is then invoked with an argument of 1, and then the IIFE is invoked by the function returned by some function

Is this correct? What object is some function defined on? Is it window/global? Or is this a JavaScript implementation feature and not a language feature?


Solution

  • The IIFE similarly looks like it is passed as a callback to some function that returns a function.

    No. In

        f(1)
    

    there is only one function call: f is called directly.

    In

    //     v v function call operator
        (f)(1)
    //  ^ ^ grouping
    

    there is still only one function call. The code is equivalent to f(1); just some redundant parens were added.

    We're not limited to calling variables. We can use any expression we want (as long as it evaluates to a function):

    (function (x) { ... })(1)
    
    // equivalent to:
         let f = function (x) { ... };
         f(1);
    // but without needing a temporary variable
    

    The only reason we can't just write function () { ... }() is that the function keyword cannot appear at the beginning of a statement (if it does, it is parsed as the beginning of a function declaration instead, not a function expression). But e.g.

    void function () { console.log("hello"); }();
    
    console.log( function (x) { return x + 1; }(1) );

    are perfectly valid statements (containing IIFEs).

    The situation is slightly different with => functions. Here we only have to worry about how far to the right the function body extends.

    (() => console.log("hello"))();

    ... needs parens around the function expression because otherwise the () at the end would be parsed as part of the function body: console.log("hello")(), which would try to call the value returned from console.log.