有没有理由使用IIFE定义module.exports?

时间:2015-09-08 17:10:31

标签: javascript node.js iife

我的团队没有任何经验丰富的JS开发人员,但是我们正在Node编写一个库,并从一个真正的JS开发人员那里得到一个建议:“我们应该使js更加模块化 - 不要污染全局命名空间并制作它对新来者更具可读性“,并告诉我们要做以下事情:

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

而不是

module.exports.nameToExpose = functionToExpose;

这有什么意义,如果有的话?后者不会制作任何由IIFE规定的本地声明,即使它确实如此,它们将是模块文件的本地声明,而不是require()整个程序的全局声明。

关于这个网站的一些谷歌搜索和讨论没有找到关于这个特定问题的任何答案,尽管我已经读过很多其他IIFE解释(并在上面的评论中总结了)。一些测试肯定会发现后者确实实际上将functionToExpose放在全局命名空间中,尽管它的原始名称记录在函数类型本身中。

3 个答案:

答案 0 :(得分:14)

几乎没有区别。 Node.js的整个想法,使用require,具有模块等,专门用于区分问题。我(小心地)说,如果你做得对,你不应该担心“污染”任何类型的全球范围。 module.exports内的任何内容都存在于该模块中。

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

  

真正的JS开发人员

召唤一个红旗的人。

  

不污染全局命名空间并使其对新来者更具可读性

如果您正确地模块化您的代码,那不应该是一个问题。 IIFE有一个时间和地点,但我认为没有理由将IIW中的所有内容包装在已经在模块内部中,它会以某种方式神奇地使代码“更模块化”或更具可读性对于“新来者”,而不是简单地使用Node.js,就像设计它一样:

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

即使它确实如此,它们也是模块文件的本地文件,而不是require()整个程序的全局。

你是对的。我不顾一切地说他的话。也许他知道一些具体的用例,他的方法过去对他很有帮助,所以我会特别问他这个问题,看看他说的是什么。除此之外,我觉得你走在正确的轨道上。

答案 1 :(得分:8)

有时这样做的原因是因为如果不这样做,那么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
        }
    }());
    
  3. 在第一个例子中,出现了两个问题。

    1. 您的变量(如foo)创建的距离远离用于从模块中导出值的位置。这可能会降低清晰度。当然,您可以在程序代码之后声明一个变量,但它仍然具有相同的范围(var s是hoisted)。另外,一般的最佳做法是预先声明所有变量,而不是这样做是需要考虑的权衡。
    2. 程序代码可能会有意或无意地弄乱您的变量,这会使事情复杂化,除非您需要(有时候这样做),否则是不可取的。
    3. 第二个示例通过为文件的该区域设置专用范围来消除这些问题。您仍然可以使用作用于整个文件的变量,但是在您不需要的变量的情况下,您可以使用更易于阅读和理解的变量。

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

      <强>更新

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

      //
      // ... lots of program code here ...
      //
      
      const foo = 'la' + 'la';  // some computed value
      
      module.exports = {
          foo : foo,
      };
      

      在上面的示例中,如果程序代码使用foo,则由于Temporal Dead Zone而导致ReferenceError崩溃,而不是接收undefined var会。这很好,因为现在你必须明确地将foo的声明移动到代码中的较早位置(如果它是故意使用的,或以其他方式修复代码。)

答案 2 :(得分:-1)

这是个好主意。有很多关于 javascript 的内容似乎突破了“现代编程”的完成方式。也许其中之一是 CommonJS 的模块化系统。但是 javascript 的演变一直沿着经典的面向对象的软件开发范式发展。很可能永远都是。

Javascript 可能会做不同的事情,但它不会做不同的事情......如果这是有道理的。

保护作用域和对象免受过度突变总是一个好主意。

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