4

我在使用 CoffeeScript 创建函数时遇到了一些麻烦,我想我错过了一些东西。对于我的用户控制器,我想为注册表单创建客户端验证。我想我错过了这一切是如何运作的一些基本的东西。

<%= form_for @user, :html => {:onsubmit => "return validate_signup_form();"} do |f| %>

CoffeeScript ( assets/users.js.coffee ):

validate_signup_form = () ->
    alert "Hi"
    return false

预期输出:

var validate_signup_form;
validate_signup_form = function() {
  alert("Hi");
  return false;
};
validate_signup_form();

实际输出:

(function() {
  var validate_signup_form;
  validate_signup_form = function() {
    alert("Hi");
    return false;
  };
}).call(this);
4

2 回答 2

6

实际上,一切都按预期进行。正如您在此处所读到的,Coffeescript 将您的代码包装在一个匿名函数中,以防止污染全局命名空间。如果您只看一下示例,您可能会错过这一点,但文档明确指出:

尽管为了清楚起见在本文档中被隐藏,但所有 CoffeeScript 输出都包装在一个匿名函数中: (function(){ ... })(); 这个安全包装器与 var 关键字的自动生成相结合,使得意外污染全局命名空间变得极其困难。

为了访问在这个人工范围内声明的对象、变量或方法,您需要使其在全局范围内显式可用,例如:

window.validate_signup_form = validate_signup_form

在您提到的情况下,我肯定会使用事件来触发该方法。

顺便说一句:方法声明中不需要空括号foo =->就可以了。

于 2011-06-21T12:50:28.800 回答
3

polarblau 的回答非常正确。也可以看看:

闭包包装器是保持文件模块化(应该如此)的好方法,因此我强烈建议不要摆脱它。请注意,在模块的外部范围内,this/@将是window,因此您只需添加一个字符即可使代码按预期工作:

@validate_signup_form = ->
  alert "Hi"
  false

您是喜欢使用@还是window.定义全局变量取决于您,但这种@风格还有另一个优点:如果您在 Node.js 应用程序中重用您的代码,那么它仍然可以工作。这些对象将附加到exports而不是window.

于 2011-06-21T19:38:17.807 回答