如何在CoffeeScript中定义全局变量?

在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下通过coffee-script编译,这样包装:

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

医生说:

如果你想创建顶级变量供其他脚本使用, 将它们作为属性附加到窗口上,或在导出对象上 CommonJS。存在操作符(下面将介绍)给出一个 如果你的目标是两者,这是一种可靠的方法,可以找出在哪里添加它们 CommonJS和浏览器:root = exports ?这个< / p >

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

123870 次浏览

由于coffee脚本没有var语句,它会自动为coffee-script中的所有变量插入该语句,这样可以防止编译后的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 ?这

这显然是一个coffee-script,所以让我们来看看它实际上编译成什么:

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

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

因此,如果exports存在,在Node.js中(或在一个写得很糟糕的网站中……)根将指向exports,否则指向this。那么this是什么呢?

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

在函数上使用.call将函数内部的this绑定到传递的第一个参数,对于浏览器来说,this现在将是window对象,对于Node.js来说,它将是全球背景下,也可以作为global对象。

但是因为你在Node.js中有require函数,所以不需要在Node.js中为global对象赋值,相反,你要为exports对象赋值,然后由require函数返回。

Coffee-Script

说了这么多,下面是你需要做的:

root = exports ? this
root.foo = -> 'Hello World'
这将在全局命名空间(不管它是什么)中声明我们的函数foo 这就是全部:)

Ivo很好地解决了这个问题,但我要提到一个你可以使用的小技巧,尽管如果你追求的是风格点,我不建议你这么做:你可以通过反勾转义直接将JavaScript代码嵌入到CoffeeScript中。

然而,这通常是一个坏主意:CoffeeScript编译器不知道这些变量,这意味着它们不会遵守正常的CoffeeScript作用域规则。所以,

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

编译,

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

现在你在不同的作用域中得到了两个__abc。正如Ivy所描述的,如果不引用全局对象,就无法从CoffeeScript代码中修改全球 foo

当然,这只是当你在coffeescript中赋值给foo时才会出现问题——如果foo在被赋予初始值后变成只读(即它是一个全局常量),那么嵌入式JavaScript解决方案可能有点可以接受(尽管仍然不推荐)。

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

添加到伊沃·韦策尔的回答是

似乎有一个exports ? this的简写语法,我只能在谷歌组发帖中找到文档/提到。

例如,在web页面中,要使一个函数全局可用,您可以再次使用@前缀声明该函数:

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


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

对我来说,@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

我认为你想要达到的目标可以简单地这样做:

在编译coffeescript时,使用"-b"参数。

__abc0 / __abc1 __abc2

就像这样:coffee -b --compile somefile.coffee whatever.js

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

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

如,

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

这是可行的,因为当调用ReferenceFunction“裸”(即func(),而不是new func()obj.func())时,通常被称为“函数调用调用模式”,总是this绑定到该执行上下文的全局对象。

上面的CoffeeScript简单地编译为(function(){ return this })();我们通过这种行为来可靠地访问全局对象。

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

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

在browserify中,global等于window

< p >,只是:

somefunc = ->
global.variable = 123

就我个人而言,我认为你太专注于在CoffeeScript中,你不能说:

let x

在主代码中。但没有什么能阻止你说

x = undefined

在你的主代码中,这将创建变量x。我想确保当你以后在函数中引用(或赋值)x时,它将使用相同的x,所以我写了这个脚本:

x = undefined


func = () ->
console.log "x = #{x}"
x = 5
console.log "x = #{x}"


func()
console.log "x = #{x}"

输出:

x = undefined
x = 5
x = 5

所以只有一个x,你可以在函数中使用。