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)
我实际上没有使用这个,但有时候希望咖啡函数有内省的名字。