如何在CoffeeScript中定义全局variables?
在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);
通过node.js下的咖啡脚本编译包装:
(function() { var bawbag; bawbag = function(x, y) { var z; return (z = (x * y)); }; bawbag(5, 10); }).call(this);
文档说:
如果您想为其他脚本创build顶级variables,请将它们作为窗口上的属性或CommonJS中的exports对象附加。 存在的操作符(如下所示)为您提供了一种可靠的方法来确定将它们添加到哪里,如果您同时针对CommonJS和浏览器:root = exports? 这个
如何在CoffeeScript中定义全局variables? “将它们附加为窗口上的属性”是什么意思?
由于咖啡脚本没有var
语句,它会自动将其插入咖啡脚本中的所有variables,这样可以防止编译的JavaScript版本将所有内容泄漏到全局名称空间中 。
所以,因为没有办法让事情有意地从事物的咖啡脚本一侧“泄漏”到全局命名空间中 ,所以需要将全局variables定义为全局对象的属性。
将它们作为属性附加在窗口上
这意味着你需要做一些像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;
首先它将检查是否定义了输出,因为试图在JavaScript中引用一个不存在的variables会产生一个SyntaxError(除非它与typeof
)
所以如果exports
存在,Node.js(或者在一个写得不好的Web站点中)的情况就是指向exports
,否则就是exports
。 那这是什么?
(function() {...}).call(this);
在一个函数上使用.call
将把函数内部的这个函数绑定到传递的第一个参数,在浏览器的情况下this
将成为window
对象,在Node.js的情况下,它将成为全局上下文 , global
对象。
但是由于Node.js中有require
函数,因此不需要为Node.js中的global
对象分配内容,而是分配给exports
对象,然后由require
函数返回。
咖啡脚本
在所有的解释之后,你需要做的是:
root = exports ? this root.foo = -> 'Hello World'
这将在全局命名空间中声明我们的函数foo
(无论发生什么)。
就这样 :)
对我来说,似乎@atomicules有最简单的答案,但我认为它可以简化多一点。 你需要在任何你想成为全局的东西之前放一个@
,这样它就可以编译成this
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
Ivo钉了它,但我会提到,有一个肮脏的技巧,你可以使用,但我不build议,如果你要风格点:你可以embeddedJavaScript代码直接在你的CoffeeScript中用反引号逃脱它。
然而,这是为什么这通常是一个坏主意:CoffeeScript编译器不知道这些variables,这意味着他们不会遵守正常的CoffeeScript范围规则。 所以,
`foo = 'bar'` foo = 'something else'
编译
foo = 'bar'; var foo = 'something else';
现在你已经有了两个不同的范围。 像Ivy所描述的那样,没有办法从CoffeeScript代码中修改全局 foo
而不引用全局对象。
当然,如果您在CoffeeScript中为foo
赋值,这只是一个问题 – 如果foo
在被赋予其初始值(即,它是一个全局常量)后变为只读,那么embedded式JavaScript解决scheme可能有点令人满意(虽然仍然不推荐)。
当您通过node.js下的coffee-script编译代码时,您可以传递-b选项。 编译后的代码将和coffeescript.org一样。
添加到Ivo Wetzel的答案
似乎有一个简短的exports ? this
语法exports ? this
exports ? this
只能在Google群组发帖中findlogging/提及。
也就是说,在一个网页中使全局可用的函数,你再次用@
前缀声明该函数:
<script type="text/coffeescript"> @aglobalfunction = aglobalfunction = () -> alert "Hello!" </script> <a href="javascript:aglobalfunction()" >Click me!</a>
我认为你所要达到的目标可以简单地做到这一点:
在编译咖啡脚本时,使用“-b”参数。
-b
/ --bare
编译没有顶级函数安全包装器的JavaScript。
所以像这样: coffee -b --compile somefile.coffee whatever.js
这将输出您的代码就像在CoffeeScript.org网站。
如果你是一个坏人(我是一个坏人),你可以像这样简单:( (->@)()
如在,
(->@)().im_a_terrible_programmer = yes console.log im_a_terrible_programmer
这是有效的,因为当调用Reference
Function
'裸'(即func()
而不是new func()
或obj.func()
)时,通常被称为“函数调用调用模式” 总是将其绑定到该执行上下文的全局对象。
上面的CoffeeScript简单地编译为(function(){ return this })()
; 所以我们正在行使这种行为来可靠地访问全局对象。
由于coffeescript本身很less使用,所以可以使用node.js或browserify提供的global
variables(以及任何后代,如coffeeify,gulp构build脚本等)。
在node.js中global
是全局名称空间。
在browserify global
等于window
。
所以,只是:
somefunc = -> global.variable = 123