CoffeeScript模块模式

在回顾Github上CoffeeScript的源代码的同时 ,我注意到大部分(如果不是全部)模块定义如下:

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

这个模式看起来像是将整个模块封装在一个匿名函数中并自行调用。

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

Harmen的回答是相当不错的,但是让我详细介绍一下CoffeeScript编译器的工作原理和原因。

当你用coffee -c foo.coffee编译某个东西的coffee -c foo.coffee ,你总会得到一个foo.js

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

这是为什么? 那么,假设你把一个任务像

 x = 'stringy string' 

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

现在假设你写了

 x = 42 

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

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

所以foo.coffeexbar.coffee中的x是完全隔离的。 这是CoffeeScript的一个重要组成部分: variables不会从一个.coffee文件泄露到另一个,除非显式导出 (通过连接到共享的全局或exports到Node.js中)。

你可以通过使用-b (“裸”)标志来覆盖这个,但是这只能用在非常特殊的情况下。 如果你用上面的例子,你会得到的输出

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

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

通过隔离不同模块的作用域,CoffeeScript编译器使您不用担心项目中的不同文件是否可能使用相同的本地variables名称。 这是在JavaScript世界中的常见做法(例如,请参阅jQuery源代码或几乎任何jQuery插件)-CoffeeScript只是为您提供帮助。

这种方法的好处是可以创build私有variables,所以不会和variables名发生冲突:

 (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 

这是类似的语法:

 (function() { }()); 

这被称为即时function。 该function是立即定义和执行的。 这个优点是你可以把所有的代码放到这个块中,然后把这个函数分配给一个全局variables,从而减less全局命名空间的污染。 它在函数内提供了一个很好的包含范围。

这是编写模块时使用的典型模式:

 var MY_MODULE = (function() { //local variables var variable1, variable2, _self = {}, etc // public API _self = { someMethod: function () { } } return _self; }()); 

不知道缺点究竟是什么,如果有人知道我会很乐意了解他们。