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

Han*_*ver 317 javascript coffeescript

在Coffeescript.org上:

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

bawbag(5, 10) 
Run Code Online (Sandbox Code Playgroud)

会编译为:

var bawbag;
bawbag = function(x, y) {
  var z;
  return (z = (x * y));
};
bawbag(5, 10);
Run Code Online (Sandbox Code Playgroud)

通过node.js下的coffee-script编译包装如下:

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

文件说:

如果要为其他要使用的脚本创建顶级变量,请将它们作为属性附加到窗口或CommonJS中的exports对象上.存在运算符(如下所述)为您提供了一种可靠的方法来确定添加它们的位置,如果您的目标是CommonJS和浏览器:root = exports?这个

如何在CoffeeScript中定义全局变量."将它们作为窗口上的属性附加"是什么意思?

Ivo*_*zel 419

由于咖啡脚本没有var声明,它会自动为咖啡脚本中的所有变量插入它,这样就可以防止编译的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;
Run Code Online (Sandbox Code Playgroud)

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

因此,如果exports存在,Node.js中的情况(或者写得很糟糕的WebSite ......)根将指向exports,否则指向this.那是什么this

(function() {...}).call(this);
Run Code Online (Sandbox Code Playgroud)

使用.call上的功能将绑定this功能里面第一个参数传递,在浏览器的情况下,this现在会是window对象,在Node.js的的情况下,这将是全球范围内它也可作为global对象.

但是由于你require在Node.js中有函数,所以不需要global在Node.js中为exports对象赋值,而是分配给require函数返回的对象.

咖啡脚本

完成所有解释之后,这就是您需要做的事情:

root = exports ? this
root.foo = -> 'Hello World'
Run Code Online (Sandbox Code Playgroud)

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

  • 甚至更短:``(出口?这个).foo = - >'Hello World'`` (12认同)
  • this.foo经常是!= window.foo但是如果你''这个'上下文已经是一个对象了.这是一个令人困惑的语法. (3认同)

Bil*_*oon 57

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

所以...

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

bawbag(5, 10)
Run Code Online (Sandbox Code Playgroud)

编译成......

this.bawbag = function(x, y) {
  var z;
  return z = x * y;
};
bawbag(5, 10);
Run Code Online (Sandbox Code Playgroud)

并在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
Run Code Online (Sandbox Code Playgroud)

  • 但是,如果你已经在另一个范围内,这将无效吗?因为那时`this`不再引用全局对象 (7认同)
  • 你不需要定义另一个变量只需使用`=>`而不是` - >`来指示coffeescript在this/global命名空间下创建函数 (2认同)
  • 这非常有用,现在我可以在单独的咖啡脚本中创建全局对象和功能 (2认同)

Tre*_*ham 33

Ivo钉了它,但我会提到你可以使用一个肮脏的技巧,但是如果你想要使用样式点我不推荐它:你可以通过使用反引号转义它来直接在你的CoffeeScript中嵌入JavaScript代码.

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

`foo = 'bar'`
foo = 'something else'
Run Code Online (Sandbox Code Playgroud)

编译成

foo = 'bar';
var foo = 'something else';
Run Code Online (Sandbox Code Playgroud)

现在你已经有两个foo不同的范围了.有没有办法修改全球 foo从CoffeeScript的代码而不引用全局对象,如常春藤描述.

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

  • @ Pier-OlivierThibault如果你想在Titanium中使用Globals你可以使用Ti.App.myGlobalVar ="ImAGlobalVar"并且不需要反引号 (2认同)

小智 11

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


ato*_*les 9

添加到Ivo Wetzel的答案

似乎有一个简写语法exports ? this,我只能在Google群组帖子中找到记录/提及的语法.

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

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

<a href="javascript:aglobalfunction()" >Click me!</a>
Run Code Online (Sandbox Code Playgroud)

  • @aglobalfunction中的'@'简单地被'this.'取代,因此编译为'this.aglobalfunction'.这是有效的,因为coffeescript包装函数(如果应用)的范围是全局范围. (9认同)

San*_*gha 9

我认为你想要实现的目标可以简单地完成:

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

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

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

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


ELL*_*BLE 7

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

如,

(->@)().im_a_terrible_programmer = yes
console.log im_a_terrible_programmer
Run Code Online (Sandbox Code Playgroud)

这个工程,调用因为当Reference一个Function"裸"(即,func()而不是new func()obj.func()),一些通常被称为"函数调用调用模式",总是绑定this到该全局对象执行上下文.

上面的CoffeeScript只是编译成(function(){ return this })(); 所以我们正在行使这种行为来可靠地访问全局对象.