我注意到在CoffeeScript中,如果我使用:
定义一个函数a = (c) -> c=1
我只能获得函数表达式:
var a;
a = function(c) {
return c = 1;
};
但是,我个人经常使用函数声明,例如:
function a(c) {
return c = 1;
}
我确实使用了第一种形式,但我想知道CoffeeScript中是否有一种生成函数声明的方法。如果没有这种方式,我想知道为什么CoffeeScript会避免这样做。我不认为只要函数声明在作用域的顶部,JSLint就会声明声明错误。
答案 0 :(得分:60)
CoffeeScript在一个地方使用函数声明(又名“命名函数”):class
定义。例如,
class Foo
编译到
var Foo;
Foo = (function() {
function Foo() {}
return Foo;
})();
根据FAQ:
,CoffeeScript不在其他地方使用函数声明的原因归咎于微软。最初,每个可以为其检索合理名称的函数都被赋予一个,但是IE 8及更低版本具有范围问题,其中命名函数被视为声明和表达式。有关详细信息,请参阅this。
简而言之:不小心使用函数声明会导致IE(pre-9)和其他JS环境之间出现不一致,因此CoffeeScript会避开它们。
答案 1 :(得分:12)
是的,你可以:
hello()
`function hello() {`
console.log 'hello'
dothings()
`}`
你通过反引号“
逃脱纯粹的JS请注意,您不能在函数体上缩进。
干杯
答案 2 :(得分:6)
使用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); }`
答案 3 :(得分:1)
不,你不能在咖啡脚本中定义一个函数,并让它在咖啡脚本中生成函数声明
即使您只是写
-> 123
生成的JS将被包装在parens中,从而使其成为函数表达式
(function() {
return 123;
});
我的猜测是,这是因为函数声明被“提升”到封闭范围的顶部,这会破坏coffeescript源的逻辑流程。
答案 4 :(得分:1)
虽然这是一篇较旧的帖子,但我想为未来的Google员工添加一些内容。
OP是正确的,因为我们不能在纯CoffeeScript中声明函数(不包括使用反向标记来逃避CoffeeScript文件中的纯JS)。
但是我们能做的是将函数绑定到窗口,并且最终会得到一些我们可以调用的东西,好像它是一个命名函数。我没有说明是一个命名函数,我提供了一种方法来做我想象的OP想要实际做的事情(在代码中的某个地方调用像foo(param)这样的函数)纯咖啡。
以下是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已经创建,如果我们在初始页面加载时调用上面的函数(在ajax调用呈现部分之前),jQuery不会看到$(&#39;#property_street_address_1&#39;)元素(相信我 - 它没有)。
所以我们需要延迟google.maps.places.Autocomplete(),直到页面上出现元素为止。
我们可以通过成功加载partial:
的Ajax回调来实现 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()
相同的事情答案 5 :(得分:1)
为什么呢?因为功能声明是邪恶的。看看这段代码
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
答案 6 :(得分:0)
试试这个:
defineFct = (name, fct)->
eval("var x = function #{name}() { return fct.call(this, arguments); }")
return x
现在以下内容将打印“true”:
foo = defineFct('foo', ()->'foo')
console.log(foo() == foo.name)
我实际上并没有使用它,但有时候希望咖啡功能有内省的名称。