为什么要将IIFE赋值给一个变量?

15

我在JavaScript和AngularJS中一直使用立即执行函数(IIFE),并采用以下结构:

方法1:

//IIFE Immediately Invoked Function Expression
(function () {


}());

然而,我经常看到以下代码,其中一个变量被赋值给了IIFE

方法2:

//IIFE Immediately Invoked Function Expression assigned to doStuff variable
var doStuff = (function () {


}());

注意: 此问题不是关于什么是此模式或什么是IIFE的问题。这个问题具体涉及使用一个返回变量在IIFE上以及它与Angular实践的关系。

在Angular中,方法1可以正常工作,但在我看到的许多原始JS示例中,使用了方法2。我的假设是,任何封装在doStuff中的东西都可以通过它来使用和调用。然而,我并不100%确定这两种方法之间的确切原因或区别,并需要一些帮助来理解何时使用不同的方法?


@Bergi - 这不是重复的问题 - 请阅读问题并看到与链接所谓的重复之处的区别。那个链接没有回答这个问题。 - atconway
2
我不确定我理解这个问题。你似乎知道IIFE的作用; 那么为什么要从IIFE中返回呢?每当您想要从表达式中返回以将值分配给doStuff时,而不仅仅执行void IIFE。如果您正在寻找用例,则应搜索“模块模式”,因为这就是具有返回值的IIFE的称呼。 - Bergi
@Bergi - 我认为您刚才发布的评论实际上是对我所发表的内容的很好的解释,也可以称之为“答案”。如果您重新打开并将该段落作为答案发布,我会点赞。不要忘记,仅因为某些事情对您来说很明显,并不意味着对OP(即我)也是如此。同样,因为它很明显,也不是关闭的理由。我需要具体的示例以及有关使用返回变量与不使用的解释。在Angular中,他们并不总是使用返回变量,然而许多JS示例确实使用了返回变量。我想知道和理解“为什么”。 - atconway
2
这已经是我第二次看到IIFE这个名字影响理解了。如果我们使用它的旧/传统名称——“自调用函数”来称呼这个设计模式,为什么有些被分配给变量,有些不会就不会神秘:因为这就是函数所做的事情。一些函数返回值,你使用一些函数不返回值。如果人们坚持认为自调用函数是错误的,那么至少称之为立即调用函数表达式。只是不要称之为IIFE——人们会忘记IIFE并不是特别/神奇的——它们只是函数。 - slebetman
@slebetman - 我认为我从 Angular 的角度出发想要表达的是,为什么我们可以有返回值为空的 IIFE,但仍然可以返回和使用公共可用函数?我正在寻找验证,即控制器被包装在 IIFE 中的 Angular 模块容器是我们仍然可以访问 IIFE 中不包含返回变量的这些函数的原因。但是控制器本身确实具有返回变量,并且在使用 app.controller 时进行了注册。 - atconway
1个回答

17

使用第二种方法的原因是,你会发现IIFE内部有返回值(通常是对象或函数)。IIFE返回的值就是最终被赋值的内容。例如:

//IIFE Immediately Invoked Function Expression assigned to doStuff variable
var doStuff = (function () {
    var privateInformationForDoStuff = 0;

    function doStuff() {
        console.log(++privateInformationForDoStuff);
    }

    return doStuff;
}());

在此,该变量最终成为对一个函数的引用,每次调用该函数时,它都会给我们比上一次更高的数字。IIFE 的存在是为了确保没有任何东西可以修改 privateInformationForDoStuff 变量,它完全是 doStuff 函数私有的。

以前常常使用这种方法(有时称为“揭示模块模式”)创建带有各种函数和可能具有仅在“模块”内共享的私有信息的对象:

var MyApp = (function() {
    var privateModuleInformation;
    var morePrivateModuleInformation;
    // ...

    function doThis() {
        // ...
    }

    function doThat() {
        // ...
    }

    function doTheOther() {
        // ...
    }

    return {
        doThis: doThis,
        doThat: doThat,
        doTheOther: doTheOther
    };
})();

在现代环境中,您将使用实际的模块,但过去并没有这个选项。


2
这非常有帮助,谢谢。我认为差距在于AngularJS不需要将变量分配给用于控制器、服务等创建的IIFE。我相信它不需要它们的原因是因为在IIFE内部,代码通过ng-app指令向使用的Angular模块容器注册自己,从而无需使用返回变量即可访问从IIFE返回的所有内容。您知道这是否是正确的解释吗? - atconway
1
@atconway: 可能吧。你会在非Angular代码中看到不返回值的IIFE。例如,这是我通常为没有本地支持String#trim的浏览器编写的polyfill:http://pastie.org/9660901(当然,它通常是更大的一部分)。 - T.J. Crowder
1
通过您在此帖子中的示例,我假设变量doStuffmyApp将用于同一.js文件中进行引用,而不是其他文件中?或者这些返回变量通常被公开用于多个.js文件中,这是常见做法吗? - atconway
2
如果上面的代码在全局范围内,那么它们将是全局变量,因此可以被同一窗口中加载的其他JavaScript使用。如果上面的代码不在全局范围内,它们就不是全局变量,因此可能无法使用。我尽量避免在我的代码中创建任何全局变量;您可以查看各种AMD(异步模块定义)机制,以加载相互依赖的多个脚本。 - T.J. Crowder
好的,我想现在有些灯泡亮了 - 在 AngularJS 中,连接 IIFE 的 '粘合剂' 是框架本身和相关模块。在原始JS中,通过全局脚本标签提供访问(如果需要)来实现“粘合剂”。然后还有一些替代方法,如 AMD,它们清理依赖关系并提供多种方法来提供每个文件或全局暴露值之间的 '粘合剂',通过定义它们之间的关系。 - atconway

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接