【发布时间】:2015-12-27 16:41:12
【问题描述】:
我是 JavaScript 新手,我正在研究以下主题:closure 和 IIFE(立即调用的函数表达式)。
所以我有以下与 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() 函数相关的示例有一些疑问。
所以第一个例子展示了闭包的概念和事实,在每个执行的函数的外部引用之后,程序到达与buildFunctions()的变量相关的内存空间 如果它的执行上下文从执行上下文堆栈中弹出。因此,所有 3 个函数的结果将始终相同,并且为 3。
这对我来说非常清楚。
第二个示例打算在我执行放入数组中的 3 个函数时获取值 0、1 和 3。
为了获得这种行为,buildFunctions2() 执行一个 for 循环,使用 IIFE 概念将函数放入数组的当前元素中,实际上: p>
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) 那么为什么我要明确地执行这些功能呢?
我错过了什么?
【问题讨论】:
-
这是“关闭”,而不是“clousure”。谷歌对这样的错别字非常宽容,但并非所有搜索都如此,所以如果你输入正确,你可能会发现更多。
-
IIFE 是一个函数调用,而您自己调用的函数返回另一个函数。这是您必须使用
fs2[0]()等调用的返回函数。 -
@GolezTrol 我知道这个话题与 clousure 概念有关,但如果你读到我的问题是不同的,它更与 IIFE 的疑问有关
标签: javascript javascript-objects iife