316

在 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 ? 这

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

4

9 回答 9

418

由于咖啡脚本没有var语句,它会自动将它插入到咖啡脚本中的所有变量中,这样就可以防止编译后的 JavaScript 版本将所有内容泄漏到全局命名空间中。

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

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

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

节点.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(或在一个写得不好的网站......)中就是这种情况,root 将指向exports,否则指向this. 那是什么this

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

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

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

咖啡脚本

在所有这些解释之后,这就是你需要做的:

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

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

于 2010-11-18T13:16:20.257 回答
59

对我来说,@atomicules 似乎有最简单的答案,但我认为它可以简化一点。你需要@在任何你想成为全局的东西之前放一个,以便它编译this.anythingthis引用全局对象。

所以...

@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-06-29T12:53:17.587 回答
33

Ivo 做到了,但我会提到你可以使用一个肮脏的技巧,但如果你想获得风格点,我不推荐它:你可以通过使用反引号将 JavaScript 代码转义来直接将 JavaScript 代码嵌入到 CoffeeScript 中。

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

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

编译为

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

现在您已经foo在不同的范围内拥有了两个 s。正如 Ivy 所描述的,如果不引用全局对象,就无法从 CoffeeScript 代码修改全局对象。 foo

当然,如果你foo在 CoffeeScript 中进行赋值,这只是一个问题——如果foo在被赋予其初始值后变为只读(即它是一个全局常量),那么嵌入式 JavaScript 解决方案方法可能有点可接受(尽管仍然不建议)。

于 2010-11-20T05:07:17.443 回答
11

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

于 2011-08-27T06:49:15.220 回答
10

我认为您想要实现的目标可以简单地像这样完成:

在编译咖啡脚本时,请使用“-b”参数。

-b/--bare 在没有顶级函数安全包装器的情况下编译 JavaScript。

所以是这样的:coffee -b --compile somefile.coffee whatever.js

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

于 2014-02-12T20:12:33.537 回答
9

添加到Ivo Wetzel 的答案

似乎有一种简写语法exports ? this,我只能在Google 群组发帖中找到记录/提及的内容。

即在网页中使函数全局可用,您再次使用@前缀声明该函数:

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

<a href="javascript:aglobalfunction()" >Click me!</a>
于 2011-09-14T09:40:39.497 回答
7

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

如中,

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

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

上面的 CoffeeScript 简单地编译为(function(){ return this })(); 所以我们正在执行该行为以可靠地访问全局对象。

于 2015-12-19T03:51:05.743 回答
4

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

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

在 browserifyglobal中等于window.

所以就:

somefunc = ->
  global.variable = 123
于 2016-10-03T12:04:53.747 回答
0

就个人而言,我认为您过于关注在 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,你可以在函数中使用它。

于 2022-01-09T22:44:58.810 回答