在显示模块模式中使用自执行匿名函数

Fra*_*ent 2 javascript design-patterns iife

只是想知道它是否是一个很好的JavaScript实践.

假设我有许多网页都调用了初始化函数"init()",在我的模式中使用IIFE在每次加载脚本时运行函数是否正确?

var foo = (function() {
    var bar = "something";

    (function init() {
        // Do something crazy that's gonna be the same across all my web pages
        // like adding an event listener or something
        // ...
        document.write('page init...');
    }());

    function privatePage1() {
        // This stuff is gonna be used only in page1.html via foo.privatePage1
        document.write('page 1' + bar);
    }

    function privatePage2() {
        // This stuff is gonna be used only in page2.html via foo.privatePage2
        document.write('page 2' + bar);
    }

    return {
        privatePage1: privatePage1,
        privatePage2: privatePage2
    }
}());
Run Code Online (Sandbox Code Playgroud)

nra*_*itz 6

这是一个相当主观的领域,但这是我的看法:

  • 当您使用模块模式时,您将为其余代码提供一组包含的功能.它本质上是一个小型图书馆.

  • 一般情况下,我不希望库在加载时任何事情,除了完全在库内部的初始化步骤(例如设置配置,实例化一些必要的对象等) - 没有任何实际影响DOM或其​​他方面显着改变了环境(这就是为什么我从来没有完全习惯像Date.js或Prototype这样改变基本对象原型的库).

  • 这有几个原因,但主要的原因是我不想担心我的库/模块的加载顺序,而只是简单地管理依赖项.独立的模块应该不会影响彼此在所有.当你在加载时操作模块中的DOM时,迟早你会意识到你的另一段代码期望DOM在某个特定时间处于特定状态,你现在必须关心你是否在此之前或之后加载您的模块.这是一个额外的复杂性,基本上隐藏在加载模块的脚本标记中.

  • 这里的另一个问题是可移植性和适应性.也许你会想要在另一个项目中使用你的模块与另一个DOM设置.也许你想要将不同的DOM元素或配置变量传递init()给特定页面上的函数.如果init()自动执行,则会失去配置机会.

所以我通常做的是将init()方法设置为返回的模块对象的属性:

var foo = (function() {

    function init() {
        // Do something crazy that's gonna be the same across all my web pages
    }

    //...

    return {
        init: init,
        // etc
    }
}());
Run Code Online (Sandbox Code Playgroud)

然后在我的代码中的其他位置调用它:

foo.init();
Run Code Online (Sandbox Code Playgroud)

是的,这为我的所有页面的初始化添加了额外的冗余代码行(尽管这可能只是另一个脚本,所以增加的权重是11个字符).但它允许我对模块初始化时进行更精细的控制,并在我(不可避免地)确定我以后需要它时提供配置参数的挂钩.