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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32463512/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 15:19:05  来源:igfitidea点击:

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

javascriptnode.jsiife

提问by Ryan Reich

My team doesn't have any experienced JS developers, but we are writing a library in Node and got a suggestion from a real JS developer that "We should make the js more modular - not to pollute the global namespace and to make it more readable to new-comers", and told us to do the following:

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

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

rather than

而不是

module.exports.nameToExpose = functionToExpose;

What's the point of this, if any? The latter does not make any local declarations that would be scoped by the IIFE, and even if it did, they would be local to the module file and not global to the whole program that require()s it.

如果有的话,这有什么意义?后者不进行任何 IIFE 范围内的局部声明,即使这样做,它们也将是模块文件的局部声明,而不是包含require()它的整个程序的全局声明。

Some Googling and poking about this site does not turn up any answers on this particular question, though there are many other explanations of IIFEs that I have read (and which are summarized in the above comment). Some testing certainly reveals that the latter does notactually put functionToExposein the global namespace, though its original name is recorded in the function type itself.

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

采纳答案by Josh Beam

Pretty much no difference. The whole idea of Node.js, using require, having modules, etc., is specifically to separate concerns. I'd say (cautiously) that if you're doing it right, you shouldn't be needing to worry about "polluting" any sort of global scope. Anything within module.exportslives in that module.

几乎没有区别。Node.js 的整个想法,使用require,拥有模块等,专门用于分离关注点。我会(谨慎地)说,如果你做得对,你就不必担心“污染”任何类型的全局范围。里面的任何东西都module.exports在那个模块中。

When you're dealing with front-end stuff, that's when the global scope becomes something of a concern, because if a function or whatever isn't scoped (i.e., in an IIFE, or other function block), it has access to the global windowobject, and everything else has access to that function.

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

a real JS developer

一个真正的 JS 开发者

Calling someone that is a red flag.

打电话给一个危险信号的人。

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

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

If you're modularizing your code correctly, that shouldn't be a concern. There's a time and a place for IIFEs, but I see no reason why wrapping everything in an IIFE, which is already inside of a module, would somehow magically make the code "more modular" or any more readable to "new comers" than by simply using Node.js like it was designed:

如果您正确地模块化您的代码,那不应该是一个问题。IIFE 是有时间和地点的,但我认为没有理由将所有内容都包装在已经在模块内部的 IIFE 中,会以某种方式神奇地使代码“更加模块化”,或者比“新来者”更具可读性只需像设计的那样使用 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.

即使是这样,它们也将是模块文件的本地文件,而不是require()它所在的整个程序的全局文件。

You are correct. I'd take whatever he's saying with a grain of salt. Maybe he knows of some specific use-cases where his approach has been helpful to him in the past, so I'd ask him specifically about that to see what he says. Other than that, I feel like you're on the right track.

你是对的。我对他所说的一切都持保留态度。也许他知道过去他的方法对他有帮助的一些特定用例,所以我会专门问他这个问题,看看他怎么说。除此之外,我觉得你走在正确的轨道上。

回答by Seth Holladay

The reason to maybe sometimesdo this is because if you don't, then any variables you need for the module.exportsobject have to be scoped to the entire file.

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

Consider these two ways.

考虑这两种方式。

  1. Without IIFE.

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

    //
    // ... lots of program code here ...
    //
    
    module.exports = (function () {
        var foo = 'la' + 'la';  // some computed value
        return {
            foo : foo
        }
    }());
    
  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
        }
    }());
    

In the first example, two problems arise.

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

  1. Your variables (like foo) are created quite far away from where they are used to export a value from the module. This can reduce clarity. Sure, you can declare a variable after the program code, but it still has the same scope (and vars are hoisted). Plus, general best practice is to declare all your variables up front, and not doing so is a tradeoff to consider.
  2. The program code can mess around with your variables, intentionally or accidentally, which complicates things and is undesirable unless you need that (sometimes you do).
  1. 您的变量(如foo)创建的位置离它们用于从模块导出值的位置很远。这会降低清晰度。当然,您可以在程序代码之后声明一个变量,但它仍然具有相同的作用域(并且vars 被提升)。另外,一般的最佳实践是预先声明所有变量,不这样做是需要考虑的权衡。
  2. 程序代码可能会有意或无意地弄乱您的变量,这会使事情复杂化并且是不可取的,除非您需要(有时您会这样做)。

The second example eliminates these problems by having a private scope for that area of the file. You can still use variables that are scoped to the entire file, but in cases where you don't need that, you can have variables that are easier to read and understand.

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

Often times we program for humans, not machines. This is an example of optimizing for the former.

很多时候,我们为人类而不是机器编程。这是针对前者进行优化的示例。

Update:

更新:

In modern versions of JavaScript, constand letare probably better solutions to the problems this pattern aims to solve. With them, you can define variables in a way that will throw errors if you make the same mistakes the IIFE is trying to protect you from.

在现代版本的 JavaScript 中,constlet可能是该模式旨在解决的问题的更好解决方案。使用它们,您可以定义变量,如果您犯了 IIFE 试图保护您免受的相同错误,则该方式将引发错误。

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

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

module.exports = {
    foo : foo,
};

In the above example, if the program code uses foo, it will crash with a ReferenceError, because of the Temporal Dead Zone, as opposed to receiving undefinedas a varwould. This is great because now you must explicitly move the declaration of footo an earlier place in the code if its use was intentional, or otherwise fix the code.

在上面的例子中,如果程序代码使用foo,它会ReferenceError因为Temporal Dead Zone而崩溃,而不是undefined像 avar那样接收。这很好,因为现在您必须明确地将 的声明移动foo到代码中的较早位置,如果它的使用是有意的,或者以其他方式修复代码。