这个 JavaScript IIFE 函数究竟是如何工作的?

How exactly works this JavaScript IIFE functions?

我是 JavaScript 的新手,我正在研究以下主题:closureIIFE(立即调用函数表达式).

所以我有下面这个跟closure概念相关的例子,很受好评:

/* Classical example as far as why closure can make your code look hard to anticipate, but understanding how works is "simple"
*/

function buildFunctions() {

    var arr = [];                       // Create an empty array

    for (var i = 0; i < 3; i++) {       

        /* Add a new function to this array, identical functions but are 3 differents functions:
        */
        arr.push(
            function() {           // It is not invoking the function, it is just creating it
                console.log(i);   // i= 0, 1, 2 
            }
        )

    }

    return arr;
}

var fs = buildFunctions();      // Call the build() function that put the 3 functions inside the array


/* When these functions are actually invoked and it looks at the 'i' variable they use the OUTER REFERENCE inside their execution context. So what will be the values? You might expect that the values will be 0, 1, 2 but this is wrong because at the end of the for loop inside the buildFunctions() function the value of the 'i' variable is 3. So when the anonymous functions inside the arrays are invoked they use the OUTER REFERENCE and the CLOSURE CONCEPT to access to the memory space related to the popped of fbuildFunctions() function that contain the variables of this function, and here the 'i' value is 3 !!!

N.B: Many people think that the result should be 0,1,2 because they think that when the function is pushed into the array it is invoked but it is not !!! The function is invoked here:
*/
fs[0]();        // Invoke the first function inside the array, the value is 3
fs[1]();        // Invoke the second function inside the array, the value is 3
fs[2]();        // Invoke the third function inside the array, the value is 3


/* What have I to do if I want this works?  (I want that the first function return 0, the second return 1 and the third return 3).
In order to preserve the value of 'i' for the inner anonymous function I am going to need a separate execution context for each of the functions that I am pushing into the array. I need a parent scope that holds the current values of 'i' variable as the loop goes on. So, the only way to get an execution context is to execute a function. To execute a function on the fly I use IIFE concept.

In this way every time that the loop runs, differently from the previous example, the anonymous inner function is executed passing to it the current value of the 'i' variable. This value is so stored in the 'j' variable in the execution context of the current performed anonymous inner function.
So at first time pass 0, at the second time pass 1, at the third time pass 3 and these 3 values are stored in the 'j' variable of the related execution context.
*/ 
function buildFunctions2() {

    var arr = [];                           // Create an empty array

    for (var i = 0; i < 3; i++) {
        arr.push(
            (function(j) {                  
                return function() {
                    console.log(j);         // print the current value  
                }
            }(i))           // I use IIFE concept to invoke the function passing the current value of the 'i' variable
        )

    }

    return arr;
}

var fs2 = buildFunctions2(); // Call th build() function that put the 3 functions inside the array

/*
When these  functions are performed don't use closure concept because it have not to use the outer reference but use the 'j' value inside the current function execution context.
*/
fs2[0]();
fs2[1]();
fs2[2]();

我非常清楚 closure 是如何工作的,但是我对前面例子的第二个例子,与 buildFunctions2() 相关的例子有一些疑问 函数。

所以第一个例子展示了闭包的概念和事实,在每个执行函数的外部引用之后,程序到达与变量相关的内存space buildFunctions() 的执行上下文从执行上下文堆栈中弹出。因此所有 3 个函数的结果将始终相同,并且将是 3.

这对我来说非常清楚。

第二个例子打算在执行数组中的3个函数时获取值0、1和3。

为了获得此行为,buildFunctions2() 执行一个 for 循环,使用 IIFE[=47= 将一个函数放入数组的当前元素中]概念,其实:

for (var i = 0; i < 3; i++) {
    arr.push(
        (function(j) {                  
            return function() {
                console.log(j);         // print the current value  
            }
        }(i))           // I use IIFE concept to invoke the function passing the current value of the 'i' variable
    )

}

据我所知,这意味着每次进入 for 循环时,都会将一个新的匿名函数添加到数组中,并将 'i' 值作为参数传递给它。所以通过这种方式我没有使用闭包概念,因为我的函数没有打印这些匿名函数上下文中的 'j' 值。我的推理对吗?

我无法理解的是:如果函数被添加到数组中并执行,为什么我还要添加:

fs2[0]();
fs2[1]();
fs2[2]();

在FireBug控制台获取结果?如果我删除这 3 行调用与我的数组的所有元素关联的函数,我将不会获得任何结果。 这对我来说似乎很奇怪,因为据我所知,使用 IIFE,我向数组添加了一个函数,并自动执行它传递给它的当前 'i' 值(即 0,1,2)那么为什么我必须明确执行这些功能?

我错过了什么?

如果您查看这部分代码:

    (function(j) {                  
        return function() {
            console.log(j);
        }
    }(i))

您会注意到有两个 function。外层是一个IIFE,当这部分代码为运行.

时会立即执行

这个外部 function 所做的是定义另一个 function (内部的​​),它使用外部函数局部的 j 的值(作为参数传递).然而,这个 function 并没有被执行(就像在第一个例子中那样),只是返回,稍后当你 运行 fs2[0]().

时执行

定义与执行的区别示例:

function fn1(a) { } // defines a function named fn1, does not execute it

fn1(123); // executes the function defined above

fn2 = function(a) { } // defines an anonymous function, does not execute it, then stores it in fn2

fn2(234); // executes the function defined above

(function(a) { } )(345); // defines an anonymous function, and executes it right away: that's an IIFE