javascript - 有关闭包和内部IIFE的一些问题

标签 javascript closures iife

我在javascriptissexy.com.上阅读此教程,直到最后一个示例。

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

最佳答案

您的问题的答案:


IIFE代表立即调用函数表达式。在JavaScript中,函数文字以两种形式之一出现:(1)完整的函数定义语句,或(2)表达式。完整的函数定义语句以function作为该语句的前导标记,这意味着该语句不是表达式,而只是函数定义。它有效地导致在当前范围内创建一个局部变量(如果在全局范围内,则为全局变量),其名称等于函数定义语句中给出的函数名称,而值等于对该函数的引用:

function myFunction() {}
myFunction();



function出现在表达式中的任何地方(不是第一个标记)时,该函数定义都被称为“表达式”,不会自动创建任何局部变量,而是可以通过分配它来存储在变量中,或立即调用在其后加上一对括号:

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关键字不作为语句中的第一个标记出现,它就会被表达并可以立即被调用以形成IIFE。


这两个return在代码设计中只是必需的。诚然,整个过程都是人为设计的,有一种简单得多的方法可以完成任务,即,一个简单的循环遍历数组并将id哈希键的值分配给从uniqueID递增的数字,但我想他们正在尝试证明IIFE。内部返回表达式从内部函数关闭的uniqueIDj计算下一个id值,并从内部IIFE返回它,然后外部返回继电器将外部IIFE的返回值返回给celebrityIDCreator函数作用域,可以在其中进行分配。
不,IIFE不需要括号。要表达函数,只需要function关键字不作为语句的第一个标记出现即可。
封闭的整个过程如下:当定义了一个函数并且包含一个其标识符未绑定到任何局部变量(用var或函数参数声明的变量)的变量时,它将关闭最接近的祖先(对解析树)具有相同标识符的本地或全局(如果无法将其绑定到任何祖先本地)。重要的一点是:这是闭包捕获的变量引用,而不是变量值。


在“上一个示例”中,位于i函数范围内的本地i周围的celebrityIDCreator闭包。重要的是,不会立即调用该函数,而是将对该函数的引用存储为id哈希键的实际值。稍后在打印过程中调用它。这意味着当函数最终被调用时,变量i已经完成了遍历数组的循环,并且现在保留其最终值103。如果立即调用了该函数,则实际上在执行过程中将对i求值。循环,它将解析为当前值,这将是正确的增量值。

在您的主要代码示例中,内部IIFE中的j关闭外部IIFE的功能参数,该参数是临时的,永远不会增加;该参数ji函数范围中与celebrityIDCreator不同的变量,永远不会关闭。而且,内部IIFE会立即被调用,因此无论如何它都会解析为变量的当前值。所以他们实际上在这里过分了。最终分配的值是正确的增量值而不是最大值的原因有两个(103)。

要点:封闭变量而不是值的封闭。


最初不需要将id属性设置为0。似乎只是一个占位符。在celebrityIDCreator中分配它时,它会被覆盖(在您的主要示例和“上一个示例”中)。而且由于在“上一个示例”中,它不是由另一个数字而是由一个函数覆盖的,所以有点奇怪。再说一遍,整个过程有些人为(对作者没有冒犯……),但是所有概念都在那里。

关于javascript - 有关闭包和内部IIFE的一些问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27351530/

相关文章:

javascript - 填充每行前面的复选框,并使用 json 和 jquery 发送选中/未选中的值和 ID

jenkins - JenkinsFile groovy 中的闭包 - 回调或委托(delegate)

Swift 如何使用 Segue 通过 View Controller 传递数据?

Javascript 闭包错误

javascript - 为什么在这种情况下使用 IIFE?

javascript - 高级 JavaScript : Why is this function wrapped in parentheses?

javascript - 添加到 url 的 Python key

javascript - 遍历数组并将项目与 html 元素匹配

javascript - popup.html 中的按钮不起作用

javascript - Javascript 函数