CoffeeScript中的函数声明

我注意到,在CoffeeScript中,如果我使用下面的方法定义一个函数:

a = (c) -> c=1 

我只能得到函数expression式

 var a; a = function(c) { return c = 1; }; 

但是,我个人经常使用函数声明 ,例如:

 function a(c) { return c = 1; } 

我使用第一种forms,但是我想知道在CoffeeScript中是否有方法生成一个函数声明。 如果没有这样的方式,我想知道为什么CoffeeScript避免这样做。 我不认为JSLint会声明一个错误,只要函数声明在范围的顶部。

CoffeeScript在一个地方使用函数声明(又名“命名函数”): class定义。 例如,

 class Foo 

编译

 var Foo; Foo = (function() { function Foo() {} return Foo; })(); 

根据常见问题解答 ,CoffeeScript不在其他地方使用函数声明:

责备微软这一个。 原来每个函数都可以有一个明智的名字,但是IE版本8和8的命名函数被视为一个声明和一个expression式。 看到这个更多的信息。

简而言之:不小心使用函数声明可能会导致IE(pre-9)和其他JS环境之间的不一致,所以CoffeeScript会避开它们。

是的你可以:

 hello() `function hello() {` console.log 'hello' dothings() `}` 

你通过反引号逃避纯粹的JS

请注意,你不能缩进你的函数体。

干杯

有一件事要记住CoffeeScript是你总是可以踢回到JavaScript。 虽然CoffeeScript不支持命名的函数声明,但您可以始终放回到JavaScript来执行它。

http://jsbin.com/iSUFazA/11/edit

 # http://jsbin.com/iSUFazA/11/edit # You cannot call a variable function prior to declaring it! # alert csAddNumbers(2,3) # bad! # CoffeeScript function csAddNumbers = (x,y) -> x+y # You can call a named function prior to # delcaring it alert "Calling jsMultiplyNumbers: " + jsMultiplyNumbers(2,3) # ok! # JavaScript named function # Backticks FTW! `function jsMultiplyNumbers(x,y) { return x * y; }` 

您也可以在CoffeeScript中编写一个大的胖子函数,然后使用反引号技巧让JavaScript调用另一个函数:

 # Coffeescript big function csSomeBigFunction = (x,y) -> z = x + y z = z * x * y # do other stuff # keep doing other stuff # Javascript named function wrapper `function jsSomeBigFunction(x,y) { return csSomeBigFunction(x,y); }` 

不,你不能在咖啡脚本中定义一个函数,并让它在咖啡脚本中生成一个函数声明

即使你只是写

 -> 123 

生成的JS将被包装在parens中,从而使其成为函数expression式

 (function() { return 123; }); 

我的猜测是,这是因为函数声明被“悬挂”到封闭作用域的顶部,这将破坏coffeescript源的逻辑stream。

虽然这是一个较旧的post,但我想为未来的Google员工添加一些对话。

OP是正确的,因为我们不能在纯CoffeeScript中声明函数(不包括使用back-ticks来在CoffeeScript文件内部转义纯JS的想法)。

但是我们可以做的就是将函数绑定到窗口上,最终我们可以调用它,就好像它是一个命名函数。 我不是说这一个命名的函数,我提供了一种方法来做我想象的OP实际上想做的事情(在代码中调用像foo(param)的函数)使用纯CoffeeScript。

下面是一个附加到coffeescript窗口的函数的例子:

 window.autocomplete_form = (e) -> autocomplete = undefined street_address_1 = $('#property_street_address_1') autocomplete = new google.maps.places.Autocomplete(street_address_1[0], {}) google.maps.event.addListener autocomplete, "place_changed", -> place = autocomplete.getPlace() i = 0 while i < place.address_components.length addr = place.address_components[i] st_num = addr.long_name if addr.types[0] is "street_number" st_name = addr.long_name if addr.types[0] is "route" $("#property_city").val addr.long_name if addr.types[0] is "locality" $("#property_state").val addr.short_name if addr.types[0] is "administrative_area_level_1" $("#property_county").val (addr.long_name).replace(new RegExp("\\bcounty\\b", "gi"), "").trim() if addr.types[0] is "administrative_area_level_2" $("#property_zip_code").val addr.long_name if addr.types[0] is "postal_code" i++ if st_num isnt "" and (st_num?) and st_num isnt "undefined" street1 = st_num + " " + st_name else street1 = st_name street_address_1.blur() setTimeout (-> street_address_1.val("").val street1 return ), 10 street_address_1.val street1 return 

这是使用Google商家信息来返回地址信息来自动填充表单。

所以我们有一个Rails应用程序被加载到页面中。 这意味着DOM已经创build,如果我们调用上面的函数初始页面加载(在Ajax调用呈现部分之前),jQuery将看不到$('#property_street_address_1')元素(相信我 – 它没有' T)。

所以我们需要延迟google.maps.places.Autocomplete(),直到元素出现在页面上。

我们可以通过成功加载部分的Ajaxcallback来实现:

  url = "/proposal/"+property_id+"/getSectionProperty" $("#targ-"+target).load url, (response, status, xhr) -> if status is 'success' console.log('Loading the autocomplete form...') window.autocomplete_form() return window.isSectionDirty = false 

所以在这里,基本上,我们正在做同样的事情调用foo()

为什么? 因为函数声明是邪恶的。 看看这个代码

 function a() { return 'a'; } console.log(a()); function a() { return 'b'; } console.log(a()); 

什么将在输出?

 b b 

如果我们使用函数定义

 var a = function() { return 'a'; } console.log(a()); a = function() { return 'b'; } console.log(a()); 

输出是:

 a b 

尝试这个:

 defineFct = (name, fct)-> eval("var x = function #{name}() { return fct.call(this, arguments); }") return x 

现在下面将打印“真实”:

 foo = defineFct('foo', ()->'foo') console.log(foo() == foo.name) 

我实际上没有使用这个,但有时候希望咖啡函数有内省的名字。