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

IT技术 javascript coffeescript
2021-02-06 23:15:50

在 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 中定义全局变量。“将它们附加为窗口上的属性”是什么意思?

6个回答

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

因此,由于无法故意从咖啡脚本方面将某些内容“泄漏”到全局命名空间中,因此您需要将全局变量定义为global object 的属性

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

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

节点.js

在 Node.js 中没有window对象,而是exports传递到包装 Node.js module的包装器中对象(参见:https : //github.com/ry/node/blob/master/src/node.js# L321 ),所以在 Node.js 中你需要做的是exports.foo = 'baz';.

现在让我们来看看它在您的文档引用中的说明:

...同时针对 CommonJS 和浏览器: root = 导出?

这显然是咖啡脚本,所以让我们看看它实际编译成什么:

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在全局命名空间中声明我们的函数(无论发生什么)。
就这样 :)

虽然我同意使用global = exports ? this. 声称“在 Node.js 的情况下它将是全局上下文......”是错误的,因为该this变量在需要或由 node.js 运行时被评估为module范围。因此,如果您期望为它设置 props 将使其在全球范围内可访问,那么您会感到失望。如果您确实想在 node.js 上下文中全局设置事物,则需要使用global变量,而不是this.
2021-03-12 23:15:50
@IvoWetzel -有什么之间的区别globalGLOBAL以及root在Node.js的对象?
2021-03-14 23:15:50
this.foo 通常是 != window.foo 但如果你是 'this' 上下文已经是一个对象。这是一个令人困惑的语法。
2021-03-17 23:15:50
试图在 JavaScript 中引用一个不存在的变量会产生一个 SyntaxError不是ReferenceError吗?
2021-03-24 23:15:50
或者更短: (exports ? this).foo = -> 'Hello World'
2021-03-31 23:15:50

对我来说,@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
这很有帮助,现在我可以在单独的咖啡脚本中创建全局对象和函数
2021-03-11 23:15:50
您不需要定义另一个变量,只需使用它=>来代替->指示 coffeescript 在 this/global 命名空间下创建函数
2021-03-19 23:15:50
但是如果您已经在另一个范围内,这将不起作用,对吗?因为 thenthis不再引用全局对象
2021-03-21 23:15:50
这是正确的,因此您可以在适当的范围内定义您的变量(并在其他范围内使用它),或者定义为window.myVariable可以在任何地方工作。
2021-03-27 23:15:50
这好多了。将 JS 转移到 CS 需要我更改很多函数调用以使用 window 对象,现在我可以恢复它
2021-03-31 23:15:50

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

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

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

编译为

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

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

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

@porneL 你是对的;我挑了一个不好的例子。关键是 CoffeeScript 编译器不会对反引号转义的 JavaScript 进行分析,因此您可能会得到奇怪的输出。
2021-03-15 23:15:50
这对我来说是一个有用的解决方案,因为我将 Titanium 与 CoffeeScript 一起使用。出口和窗口对象在那里不存在。
2021-03-16 23:15:50
这是正确的答案,至少对于 Node.js。expect = require('chai').expect;使expect变量在我所有的测试文件中可用!
2021-03-16 23:15:50
实际上这只是一个局部foo变量,因为var提升(JS 提前扫描所有var声明并将它们解释为好像它们位于函数的顶部)
2021-03-20 23:15:50
@Pier-OlivierThibault 如果你想在 Titanium 中使用 Globals,你可以使用 Ti.App.myGlobalVar = "ImAGlobalVar" 并且不需要反引号
2021-03-27 23:15:50

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

@Harry - -b/--bare直接在coffee命令之后。
2021-03-14 23:15:50
如何?我在哪里放置 -b 选项?
2021-03-18 23:15:50

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

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

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

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

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