CoffeeScript module的模式

IT技术 javascript node.js coffeescript
2021-03-15 07:03:27

在 Github 上查看 CoffeeScript源代码时,我注意到大多数(如果不是全部)module定义如下:

(function() {
    ...
}).call(this);

这种模式看起来像是将整个module包装在一个匿名函数中并调用自身。

这种方法的优点(和缺点)是什么?是否有其他方法可以实现相同的目标?

3个回答

Harmen 的回答非常好,但让我详细说明 CoffeeScript 编译器在何处完成此操作以及原因。

当你用 编译一些东西时coffee -c foo.coffee,你总是会得到一个foo.js看起来像这样的:

(function() {
  ...
}).call(this);

这是为什么?好吧,假设你把这样的作业

x = 'stringy string'

foo.coffee. 当它看到时,编译器会问:是否x已经存在于这个范围或外部范围内?如果没有,它会var x在 JavaScript 输出中该范围的顶部放置一个声明。

现在假设你写

x = 42

in bar.coffee,编译两者,并连接foo.jsbar.js进行部署。你会得到

(function() {
  var x;
  x = 'stringy string';
  ...
}).call(this);
(function() {
  var x;
  x = 42;
  ...
}).call(this);

所以xinfoo.coffeexinbar.coffee是完全隔离的。这是 CoffeeScript 的一个重要部分:变量永远不会从一个 .coffee 文件泄漏到另一个文件,除非明确导出(通过附加到共享全局或exports在 Node.js 中)。

您可以通过使用-b("bare") 标志来覆盖它coffee,但这只能在非常特殊的情况下使用。如果你在上面的例子中使用它,你得到的输出将是

var x;
x = 'stringy string';
...
var x;
x = 42;
...

这可能会产生可怕的后果。为了测试这个自己,尝试添加setTimeout (-> alert x), 1foo.coffee请注意,您不必自己连接两个 JS 文件——如果您使用两个单独的<script>标签将它们包含在一个页面上,它们仍然可以有效地作为一个文件运行。

通过隔离不同module的作用域,CoffeeScript 编译器使您免于担心项目中的不同文件是否可能使用相同的局部变量名称。这是 JavaScript 世界中的常见做法(例如,请参阅jQuery 源代码,或几乎所有 jQuery 插件)——CoffeeScript 会为您处理。

谁在玩这样的全局变量?我不会考虑在没有课程或闭包的情况下做任何事情。必须明确导出是令人讨厌的。
2021-04-28 07:03:27
你的回答写得很好,真的帮助我更好地理解 CoffeeScript(和 JavaScript)......谢谢!
2021-05-02 07:03:27
我在开发 angularjs 时开始使用 coffeescript。Andularjs 策略是杀死所有全局变量,所以 -b 标签在我的情况下就足够了 :)
2021-05-14 07:03:27

这种方法的好处是它创建了私有变量,所以不会与变量名发生任何冲突:

(function() {
  var privateVar = 'test';
  alert(privateVar); // test
})();

alert(typeof privateVar); // undefined

的添加.call(this)使this关键字引用的值与其在函数外引用的值相同。如果不加,this关键字会自动引用全局对象。

一个显示差异的小例子如下:

function coffee(){
  this.val = 'test';
  this.module = (function(){
    return this.val;
  }).call(this);
}

var instance = new coffee();
alert(instance.module); // test

function coffee(){
  this.val = 'test';
  this.module = (function(){
    return this.val;
  })();
}

var instance = new coffee();
alert(typeof instance.module); // undefined
好答案。谢谢你的帮助!
2021-04-16 07:03:27

这是与此类似的语法:

(function() {

}());

这称为立即函数。该函数被定义并立即执行。这样做的优点是您可以将所有代码放在这个块中,并将函数分配给单个全局变量,从而减少全局命名空间污染。它在函数内提供了一个很好的包含范围。

这是我在编写module时使用的典型模式:

var MY_MODULE = (function() {
    //local variables
    var variable1,
        variable2,
        _self = {},
        etc

    // public API
    _self = {
       someMethod: function () {

       }
    }

    return _self;
}());

不确定缺点可能是什么,如果其他人知道任何缺点,我很乐意了解它们。

不,这不是相关的答案。他特别问 (function(){}).call(this),而不是你举例的 (function(){})()。Harmen 的回答是中肯的。
2021-04-15 07:03:27
我想说的缺点是 1)你必须更努力地工作来跨module共享状态(至少在 CoffeeScript 中——在 JavaScript 中,你可以省略var,但通常不鼓励这样做,例如 jsLint),以及 2)有一个来自额外函数调用和字节的微小开销。但在 99% 的情况下,额外的安全是值得的。
2021-04-18 07:03:27