在Coffeescript.org上:

bawbag = (x, y) ->
    z = (x * y)

bawbag(5, 10) 


将编译为:

var bawbag;
bawbag = function(x, y) {
  var z;
  return (z = (x * y));
};
bawbag(5, 10);


通过Coffee-script在节点下编译.js将其包装为:

(function() {
  var bawbag;
  bawbag = function(x, y) {
    var z;
    return (z = (x * y));
  };
  bawbag(5, 10);
}).call(this);


文档说:


如果您要为以下内容创建顶级变量其他要使用的脚本,
将它们作为属性附加到窗口或CommonJS中的Exports对象上。如果您同时针对CommonJS和浏览器,那么existential操作符(如下所述)为您提供了一种可靠的方法来找出将它们添加到何处:root = exports? this


然后如何在CoffeeScript中定义全局变量。 “将它们作为窗口的属性附加”是什么意思?

评论

请注意,使用全局变量是不好的,c2.com / cgi / wiki?GlobalVariablesAreBad,甚至认为是有害的,c2.com / cgi / wiki?GotoConsideredHarmful。实际上,根本没有理由在JavaScript中使用它们,因为您拥有诸如闭包之类的强大功能,可以解决您正在使用全局变量来解决的大多数问题。

@Evgeny虽然我在这里同意您的观点,但在某些情况下,有必要创建一个中央“ app”对象并为其附加模块。

中心对象可以保存到现有的全局状态对象中,例如窗口对象或导出对象。无需创建全局变量。

@Evgeny全局变量保存为窗口对象(或nodejs上的全局对象)的属性

是的,拥有全局变量并不是一件坏事。愚蠢的做法是不加考虑地使您的应用程序崩溃。声明一个并将其用作像jQuery之类的适配器工厂或某种命名空间确实是很常见的做法。

#1 楼

由于coffee脚本没有var语句,因此它会自动将其插入coffee脚本中的所有变量,这样可以防止已编译的JavaScript版本将所有内容泄漏到全局名称空间中。

因此,由于没有办法故意从咖啡脚本方面使某些内容“泄漏”到全局名称空间中,因此您需要将全局变量定义为全局对象的属性。 />

将它们作为属性附加在窗口上


这意味着您需要执行类似window.foo = 'baz';的操作,该操作可以处理浏览器的情况,因为全局对象是window

Node.js

在Node.js中没有window对象,而是将exports对象传递到包装Node.js模块的包装器中(请参阅:https://github.com/ry/node/blob/master/src/node.js#L321),因此在Node.js中,您需要做的是exports.foo = 'baz';

现在让我们看一下它在文档中的引用中所声明的内容:


...针对CommonJS和浏览器:root = exports?这


这显然是咖啡脚本,因此让我们看一下它实际编译成的内容:

var root;
root = (typeof exports !== "undefined" && exports !== null) ? exports : this;


首先它会检查是否定义了exports,因为尝试在JavaScript中引用不存在的变量会产生SyntaxError(除非与typeof一起使用时除外)

因此,如果exports存在,则在Node中就是这种情况.js(或写得不好的WebSite中的...)根目录将指向exports,否则指向this。那么this是什么?

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


在函数上使用.call会将函数内部的this绑定到传递的第一个参数,如果浏览器this现在是window对象,如果使用Node.js,它将是全局上下文,也可以作为global对象使用。

但是,由于您在Node.js中具有require函数,因此无需在Node.js中为global对象分配某些内容,而是将其分配给exports对象,然后由require函数返回该对象。

咖啡脚本

经过上述所有说明之后,您需要执行以下操作:

root = exports ? this
root.foo = -> 'Hello World'


这将在全局变量中声明我们的函数foo命名空间(无论碰巧是什么)。
就这样:)

评论


@IvoWetzel-node.js中的全局,GLOBAL和根对象之间有什么区别?

– Aadit M Shah
2011年12月2日,下午5:10

试图在JavaScript中引用不存在的变量,否则会产生SyntaxError。您不是说ReferenceError吗?

– alex
2012-2-22在2:24

甚至更短:(exports?this).foo =->'Hello World'

–丹恩·奥康纳(Dane O'Connor)
2012年6月6日15:43

this.foo通常是!= window.foo,尽管如果您是'this'上下文已经是一个对象。这是一个令人困惑的语法。

–凯文
2012年10月21日,下午3:52

虽然我同意使用global = export?这个。声称“在Node.js的情况下将是全局上下文...”的说法是错误的,因为在node.js要求或运行此变量时,此变量被评估为模块范围。因此,如果您希望为其设置道具将使其在全球范围内均可使用,那么您将感到失望。如果确实要在node.js上下文中全局设置,则需要使用全局变量,而不是全局变量。

– KFL
2014年9月1日9:08



#2 楼

对我来说,@atomicules似乎是最简单的答案,但我认为它可以进一步简化。您需要将@放在要成为全局对象的任何内容之前,以便将其编译为this.anything,并且this引用全局对象。

......

@bawbag = (x, y) ->
    z = (x * y)

bawbag(5, 10)


编译为...

this.bawbag = function(x, y) {
  var z;
  return z = x * y;
};
bawbag(5, 10);

并在node.js给定的包装器的内部和外部工作

(function() {
    this.bawbag = function(x, y) {
      var z;
      return z = x * y;
    };
    console.log(bawbag(5,13)) // works here
}).call(this);

console.log(bawbag(5,11)) // works here


评论


但这如果您已经在另一个示波器中就行不通,对吗?因为这样,它不再引用全局对象

–俞宣伟
2012年8月8日,0:02

没错,因此您可以在适当的范围内定义变量(并在其他范围内使用),也可以定义为在任何地方都可以使用的window.myVariable。

–比利·穆恩(Billy Moon)
2012年8月8日在7:36

您不需要定义另一个变量,只需使用=>而不是->即可指示coffeescript在this / global命名空间下创建函数

–里卡多·维拉米尔(Ricardo Villamil)
2013年4月30日15:56

这很有用,现在我可以在单独的Coffee脚本中创建全局对象和函数

–迭戈·费尔南多·穆里略·瓦伦奇
2014年1月31日16:00



这样好多了。将JS转移到CS需要我更改许多函数调用以使用window对象,现在我可以还原该函数了

–卡斯拉夫
2014年3月27日13:59

#3 楼

Ivo做到了这一点,但是我要提到,有一个肮脏的技巧可以使用,但是如果您要获取样式点,我不建议您这样做:您可以通过使用反引号将其转义,从而将JavaScript代码直接嵌入到CoffeeScript中。

但是,这通常是一个坏主意,原因如下:CoffeeScript编译器没有意识到这些变量,这意味着它们将不遵守正常的CoffeeScript范围规则。因此,

`foo = 'bar'`
foo = 'something else'


编译为

foo = 'bar';
var foo = 'something else';


现在,您拥有两个不同的foo范围。正如常春藤所描述的,没有办法从CoffeeScript代码中修改全局foo,而无需引用全局对象。

当然,只有在CoffeeScript中对foo进行赋值时,这才是问题-如果foo变成了在给定其初始值(即,它是一个全局常量)后为只读,那么嵌入式JavaScript解决方案方法可能还算可以接受(尽管仍然不建议这样做)。

评论


这对我来说是一个有用的解决方案,因为我将Titanium与CoffeeScript一起使用。导出和窗口对象在那里不存在。

–彼尔·奥利维尔·蒂博(Pier-Olivier Thibault)
2012年1月25日13:44

实际上,由于var提升,这只是一个局部foo变量(JS会向前扫描所有var声明,并将它们解释为好像在函数顶部一样)

–内核
2012年4月24日在21:42

@porneL你是正确的;我选了一个不好的例子。关键是,CoffeeScript编译器不会对反引号转义的JavaScript进行任何分析,因此您可以获得奇数输出。

–特雷弗·伯纳姆
2012年4月25日下午0:51

@ Pier-OlivierThibault如果要在Titanium中使用Globals,则可以使用Ti.App.myGlobalVar =“ ImAGlobalVar”,不需要反引号

–Jakob Lnr
2012年7月30日在8:40

至少对于Node.js,这是正确的答案。做期望= require('chai')。expect;使期望变量在我所有的测试文件中都可用!

– pocesar
2013年6月23日下午5:51

#4 楼

通过node.js下的coffee-script编译代码时,可以传递-b选项。
编译后的代码将与coffeescript.org上的代码相同。

评论


怎么样?我在哪里放置-b选项?

–哈里
2014年1月17日在8:32

@Harry--b / --bare直接在执行咖啡命令后执行。

– ocodo
2014年6月14日下午16:17

#5 楼

要添加到Ivo Wetzel的答案中,

似乎存在exports ? this的简写语法,我只能在Google网上论坛发帖中找到记录/提及的内容。

即在网页中使某个功能全局可用时,您可以再次使用@前缀声明该功能:

<script type="text/coffeescript">
    @aglobalfunction = aglobalfunction = () ->
         alert "Hello!"
</script>

<a href="javascript:aglobalfunction()" >Click me!</a>


评论


@aglobalfunction中的“ @”被“ this。”简单替换,因此编译为“ this.aglobalfunction”。之所以可行,是因为coffeescript包装函数的作用域(如果应用)是全局作用域。

–克里斯
2011年11月9日14:38

#6 楼

我认为您可以尝试通过以下方式轻松实现目标:

在编译coffeescript时,请使用“ -b”参数。

-b / --bare编译没有顶级功能安全包装器的JavaScript。

类似这样:coffee -b --compile somefile.coffee whatever.js

这将输出您的代码,就像在CoffeeScript.org网站中一样。

#7 楼

如果您是坏人(我是坏人。),您可以像这样简单:(->@)()

例如,

(->@)().im_a_terrible_programmer = yes
console.log im_a_terrible_programmer



之所以行之有效,是因为当将Reference调用到Function'bare'(即func(),而不是new func()obj.func())时,通常被称为“函数调用调用模式”将this绑定到该执行上下文的全局对象。

上面的CoffeeScript只需编译为(function(){ return this })()即可;因此我们正在行使该行为以可靠地访问全局对象。

评论


这太棒了!

–metalim
16-4-6在21:41

唯一对我有用的东西。讨厌CoffeeScript。

–pcv
16年7月1日在19:59

喜欢CoffeeScript。到目前为止,它是目前最好的编程语言。太糟糕了,它是作为一个业余项目创建和维护的,导致其使用模式混乱和愚蠢。

–metalim
19年4月26日在15:24

#8 楼

由于coffeescript很少单独使用,因此可以使用node.js或browserify提供的global变量(以及任何后代,例如coffeeify,gulp构建脚本等)。

在node.js中,global是全局名称空间。

在browserify中,global等于window

所以,只需:


somefunc = ->
  global.variable = 123