CoffeeScript模块的模式

Jam*_*Sun 29 javascript node.js coffeescript

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

(function() {
    ...
}).call(this);
Run Code Online (Sandbox Code Playgroud)

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

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

Tre*_*ham 78

Harmen的答案非常好,但让我详细说明CoffeeScript编译器在何处完成这一点以及为什么.

当你用它编译东西时coffee -c foo.coffee,你总会得到一个foo.js如下所示:

(function() {
  ...
}).call(this);
Run Code Online (Sandbox Code Playgroud)

这是为什么?好吧,假设你做了一个类似的任务

x = 'stringy string'
Run Code Online (Sandbox Code Playgroud)

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

现在假设你写

x = 42
Run Code Online (Sandbox Code Playgroud)

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

(function() {
  var x;
  x = 'stringy string';
  ...
}).call(this);
(function() {
  var x;
  x = 42;
  ...
}).call(this);
Run Code Online (Sandbox Code Playgroud)

所以xin foo.coffeexin bar.coffee完全是相互隔离的.这是CoffeeScript的一个重要部分:除非显式导出(通过附加到共享全局或exportsNode.js),变量永远不会从一个.coffee文件泄漏到另一个.coffee文件.

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

var x;
x = 'stringy string';
...
var x;
x = 42;
...
Run Code Online (Sandbox Code Playgroud)

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

通过隔离不同模块的范围,CoffeeScript编译器可以避免担心项目中的不同文件是否可能使用相同的本地变量名称.这是JavaScript世界中的常见做法(例如,参见jQuery源代码,或者几乎任何jQuery插件)-CoffeeScript只是为您处理它.

  • 你的答案写得很好,真的帮助我更好地理解CoffeeScript(和JavaScript)......谢谢! (4认同)

Har*_*men 19

这种方法的好处是它创建了私有变量,因此不会与变量名冲突:

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

alert(typeof privateVar); // undefined
Run Code Online (Sandbox Code Playgroud)

添加.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
Run Code Online (Sandbox Code Playgroud)