是否有任何理由使用 IIFE 定义 module.exports?

Is there any reason to define module.exports using an IIFE?

我的团队没有任何经验丰富的 JS 开发人员,但我们正在用 Node 编写一个库,并得到了一位真正的 JS 开发人员的建议 "We should make the js more modular - not to pollute the global namespace and to make it more readable to new-comers",并告诉我们执行以下操作:

module.exports = (function(){
      return {
         nameToExpose: functionToExpose
         ...
    };
})();

而不是

module.exports.nameToExpose = functionToExpose;

如果有的话,这有什么意义?后者不做任何将由 IIFE 限定范围的局部声明,即使它做了,它们对于模块文件也是局部的,而不是对 require() 所在的整个程序全局的。

虽然我读过很多关于 IIFE 的其他解释(并且在上面的评论中进行了总结),但是关于这个站点的一些谷歌搜索和搜索并没有找到任何关于这个特定问题的答案。一些测试肯定表明后者 而不是 实际上将 functionToExpose 放在全局命名空间中,尽管它的原始名称记录在函数类型本身中。

几乎没有区别。 Node.js、使用require、拥有模块等的整个想法,专门用于分离关注点。我会(谨慎地)说,如果你做对了,你就不需要担心 "polluting" 任何类型的全局范围。 module.exports 中的任何内容都存在于该模块中。

当你处理前端的东西时,全局范围就会成为一个问题,因为如果一个函数或任何不在范围内的东西(即在 IIFE 或其他函数块中),它可以访问全局 window 对象,其他所有对象都可以访问该函数。

a real JS developer

打电话给某人是危险信号。

not to pollute the global namespace and to make it more readable to new-comers

如果您正确地模块化了您的代码,那应该不是问题。 IIFE 有时间和地点,但我看不出为什么将所有内容都包装在 IIFE 中,它 已经在模块 内部,会以某种方式神奇地使代码 "more modular"或者比 "new comers" 更易读,而不是像设计的那样简单地使用 Node.js:

module.exports = function() { ... } // whatever

and even if it did, they would be local to the module file and not global to the whole program that require()s it.

你是对的。我会对他说的任何话持保留态度。也许他知道他的方法在过去对他有帮助的一些特定用例,所以我会具体询问他,看看他说了什么。除此之外,我觉得你在正确的轨道上。

可能有时这样做的原因是,如果不这样做,那么 module.exports 对象所需的任何变量都必须限定在整个范围内文件。

考虑这两种方式。

  1. 没有 IIFE。

    var foo = 'la' + 'la';  // some computed value
    
    //
    // ... lots of program code here ...
    //
    
    module.exports = {
        foo : foo,
    };
    
  2. 有 IIFE。

    //
    // ... lots of program code here ...
    //
    
    module.exports = (function () {
        var foo = 'la' + 'la';  // some computed value
        return {
            foo : foo
        }
    }());
    

在第一个例子中,出现了两个问题。

  1. 您的变量(如 foo)的创建位置远离它们用于从模块导出值的位置。这会降低清晰度。当然,您可以在程序代码之后声明一个变量,但它仍然具有相同的作用域(varhoisted)。另外,一般的最佳做法是预先声明所有变量,不这样做是一种权衡。
  2. 程序代码可能会有意或无意地弄乱您的变量,这会使事情变得复杂并且不受欢迎,除非您需要(有时您需要)。

第二个示例通过为该文件区域设置私有范围来消除这些问题。您仍然可以使用作用域为整个文件的变量,但在不需要的情况下,您可以使用更易于阅读和理解的变量。

我们经常为人类而不是机器编程。这是针对前者优化的一个例子。

更新:

在 JavaScript 的现代版本中,const and let 可能是此模式旨在解决的问题的更好解决方案。有了它们,您可以定义变量,如果您犯了 IIFE 试图保护您免受的相同错误,就会抛出错误。

//
// ... lots of program code here ...
//

const foo = 'la' + 'la';  // some computed value

module.exports = {
    foo : foo,
};

在上面的示例中,如果程序代码使用 foo,它将因 ReferenceError 而崩溃,因为 Temporal Dead Zone,而不是接收 undefined就像 var 那样。这很棒,因为现在您必须明确地将 foo 的声明移至代码中较早的位置(如果它是有意使用的),否则请修复代码。

这是个好主意。关于 javascript 的很多内容似乎都在挑战 'modern programming' 的完成方式。也许其中之一就是 CommonJS 的模块化系统。但是 javascript 的发展一直沿着经典的面向对象的软件开发范式进行。它很可能永远都是。

Javascript 可能会做不同的事情,但不会做不同的事情......如果这有意义的话。

保护范围和对象免受过度突变始终是个好主意。

https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898