我正在javascriptissexy.com.上阅读这个tutualial,直到最后一个例子。
function celebrityIDCreator (theCelebrities) {
var i;
var uniqueID = 100;
for (i = 0; i < theCelebrities.length; i++) {
theCelebrities[i]["id"] = function (j) { // the j parametric variable is the i passed in on invocation of this IIFE
return function () {
return uniqueID + j; // each iteration of the for loop passes the current value of i into this IIFE and it saves the correct value to the array
} (); // BY adding () at the end of this function, we are executing it immediately and returning just the value of uniqueID + j, instead of returning a function.
} (i); // immediately invoke the function passing the i variable as a parameter
}
return theCelebrities;
}
var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0}, {name:"Willis", id:0}];
var createIdForActionCelebs = celebrityIDCreator (actionCelebs);
var stalloneID = createIdForActionCelebs [0];
console.log(stalloneID.id); // 100
var cruiseID = createIdForActionCelebs [1];
console.log(cruiseID.id); // 101
首先,我没有看到IIFE,或者至少在我熟悉的语法中,其中有(function()...
带有前导左侧括号。此外,
return function () {
return uniqueID + j; // each iteration of the for loop passes the current value of i into this IIFE and it saves the correct value to the array
} ();
为什么这两个returns
?如果这意味着IIFE不需要周围的括号?另外,j
如何不像前一个例子中i
那样立即增加到数组的长度?关于访问theCelebrities[i]["id"] = function (j) {
参数的元素id
的行actionCelebs
。为什么最初需要为每个元素将该属性设置为0
。
上一个例子
// This example is explained in detail below (just after this code box).
function celebrityIDCreator (theCelebrities) {
var i;
var uniqueID = 100;
for (i = 0; i < theCelebrities.length; i++) {
theCelebrities[i]["id"] = function () {
return uniqueID + i;
}
}
return theCelebrities;
}
var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0}, {name:"Willis", id:0}];
var createIdForActionCelebs = celebrityIDCreator (actionCelebs);
var stalloneID = createIdForActionCelebs [0];
console.log(stalloneID.id()); // 103
此处所有值都设置为103
答案 0 :(得分:2)
您的问题的答案:
IIFE代表立即调用函数表达式。在JavaScript中,函数文字以两种形式之一出现:(1)完整函数定义语句,或(2)表达式。完整函数定义语句具有function
作为语句的前导标记,这意味着该语句不是表达式,而只是函数定义。它有效地导致在当前作用域中创建一个本地(或全局范围的全局范围)变量,其名称等于函数定义语句中给出的函数名,并且值等于对函数的引用:
function myFunction() {}
myFunction();
当function
出现在表达式中的任何地方(不是作为第一个标记)时,函数定义被称为&#34;表达式&#34;并且不会自动创建任何局部变量,但可以通过分配它来存储在变量中,或者通过用一对括号跟随它来立即调用:
var func = function() { return 7; };
alert(func()); // 7
var funcRes = function() { return 3; }();
alert(funcRes); // 3
严格地说,术语IIFE可以引用任何上下文,其中函数定义被表达化,然后通过用一对括号跟随它来立即调用。您可以在代码示例中看到它们使用返回uniqueID + j
的函数执行此操作,并且它们也使用包含所述函数的函数执行此操作,并简单地将其返回值转发到其父作用域,因此它们都符合IIFE的条件
根据我的经验,术语IIFE最常用于指代包含整个陈述的IIFE,因此前导左括号对于表达函数定义是必要的,例如:
(function() {
var localVar = 3;
alert(localVar);
})();
我认为这就是为什么你发现代码示例略有意外的原因。但是,根据对IIFE的严格定义,代码示例中的这两个函数定义无疑都符合IIFE的要求;只要function
关键字 not 作为语句中的第一个标记出现,它就会被表达化,并且可以立即调用以形成IIFE。
这两个return
只是代码设计的一部分。不可否认,整个过程非常简单,并且有一种更简单的方法来完成任务,即循环遍历数组的简单循环,并将id
散列键的值分配给从{增加的数字{1}},但我想他们正试图展示IIFE。内部返回表达式计算来自uniqueID
和uniqueID
的下一个id值,它们都被内部函数关闭,并从内部IIFE返回,然后从外部返回值返回值外部IIFE返回j
函数范围,可以在其中分配。
不,IIFE不需要周围的括号。要表达函数,所需的只是celebrityIDCreator
关键字不作为语句的第一个标记出现。
完整的闭包过程如下:当一个函数被定义并包含一个变量,其标识符不绑定到任何局部变量(用function
或函数参数声明的变量)时,它就会关闭围绕最近的祖先(思考解析树)本地具有相同的标识符,或全局如果它不能绑定到任何祖先的本地。重要的是:它是由闭包捕获的变量引用,不 变量值。
在&#34;上一个例子&#34;位于var
函数范围内的本地i
周围的i
个闭包。重要的是,函数不立即被调用,但对函数的引用被存储为celebrityIDCreator
散列键的实际值。稍后在打印期间调用它。这意味着当函数最终被调用时,变量id
已经完成循环数组,并且现在保留其最终值103.如果函数已被立即调用,则i
将实际上是在循环期间进行评估,它将解析为当前值,这将是正确的递增值。
在主代码示例中,内部IIFE中的i
围绕外部IIFE的函数参数进行闭包,这是临时的,永远不会递增;该参数j
是与j
函数范围中的i
不同的变量,它永远不会关闭。此外,内部IIFE正在被立即调用,因此它无论如何都会解析为变量的当前值。所以他们实际上在这里过度了;最终指定值是正确的递增值而不是最大值(103)有两个原因。
要点:围绕变量关闭闭包,而不是值。
celebrityIDCreator
属性最初不需要设置为0;这似乎只是一个占位符。在id
中分配时,它会被覆盖(在您的主要示例和#34;上一个示例&#34;中)。因为在&#34;之前的例子&#34;它不是被另一个数字覆盖而是通过函数覆盖,这有点奇怪。同样,整个事情有点做作(对作者没有冒犯......),但所有的概念都存在。