在Github上查看CoffeeScript的源代码时,我注意到大多数(如果不是全部)模块定义如下:
(function() { ... }).call(this);
这种模式看起来像是将整个模块包装在一个匿名函数中并调用自身。
这种方法的优点(和缺点)是什么?还有其他方法可以实现相同的目标吗?
Harmen的答案是相当不错的,但让我详细说明一下CoffeeScript编译器在何处完成此操作以及原因。
当您使用编译内容时coffee -c foo.coffee,总会得到foo.js如下所示的内容:
coffee -c foo.coffee
foo.js
这是为什么?好吧,假设您输入了
x = 'stringy string'
在中foo.coffee。看到这种情况时,编译器会问:x该范围或外部范围中是否已经存在?如果不是,它将var x在JavaScript输出中的该范围的顶部放置一个声明。
foo.coffee
x
var x
现在假设你写
x = 42
在中bar.coffee,同时进行编译和连接foo.js以bar.js进行部署。你会得到
bar.coffee
bar.js
(function() { var x; x = 'stringy string'; ... }).call(this); (function() { var x; x = 42; ... }).call(this);
因此xin foo.coffee和xin bar.coffee完全相互隔离。这是CoffeeScript的重要组成部分: 除非明确导出 (通过附加到共享的全局文件或exportsNode.js中), 否则变量从一个.coffee文件不会泄漏到另一个文件 。
exports
您可以通过使用-b(“ bare”)标志来覆盖它coffee,但这仅应在非常特殊的情况下使用。如果您在上面的示例中使用了它,则输出将是
-b
coffee
var x; x = 'stringy string'; ... var x; x = 42; ...
这可能会带来可怕的后果。为了测试这个自己,尝试添加setTimeout (-> alert x), 1在foo.coffee。请注意,您不必自己连接两个JS文件- 如果您使用两个单独的<script>标签将它们包含在页面中,它们仍然可以作为一个文件有效地运行。
setTimeout (-> alert x), 1
<script>
通过隔离不同模块的作用域,CoffeeScript编译器使您不必担心项目中的不同文件是否可能使用相同的局部变量名称。这是JavaScript世界中的常见做法(例如,参见jQuery源或几乎所有jQuery插件),CoffeeScript会为您处理。