我注意到在 CoffeeScript 中,如果我使用以下方式定义函数:
a = (c) -> c=1
我只能得到函数表达式:
var a;
a = function(c) {
return c = 1;
};
但是,我个人经常使用函数声明,例如:
function a(c) {
return c = 1;
}
我确实使用第一种形式,但我想知道 CoffeeScript 中是否有办法生成函数声明。如果没有这样的方法,我想知道为什么 CoffeeScript 避免这样做。我认为 JSLint 不会报声明错误,只要该函数是在作用域的顶部声明的。
CoffeeScript 仅在一处使用函数声明(又名“命名函数”):
class
定义。例如,
class Foo
编译为
var Foo;
Foo = (function() {
function Foo() {}
return Foo;
})();
根据 FAQ,CoffeeScript 不在其他地方使用函数声明的原因:
将此归咎于微软。最初,每个可以为其检索到合理名称的函数都会被赋予一个名称,但 IE 版本 8 及以下版本存在范围界定问题,即命名函数既被视为声明又被视为表达式。请参阅此了解更多信息。
简而言之:不小心使用函数声明可能会导致 IE(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将被包裹在括号中,从而使其成为函数表达式
(function() {
return 123;
});
我的猜测是,这是因为函数声明被“提升”到封闭范围的顶部,这会破坏 Coffeescript 源代码的逻辑流程。
虽然这是一篇较旧的帖子,但我想为未来的 Google 员工在对话中添加一些内容。
OP 是正确的,因为我们不能在纯 CoffeeScript 中声明函数(不包括在 CoffeeScript 文件中使用反引号来转义纯 JS 的想法)。
但是我们可以做的是将函数绑定到窗口,并且本质上最终得到我们可以调用的东西,就好像它是一个命名函数一样。我并不是说这个is是一个命名函数,我提供了一种方法来使用纯CoffeeScript来做我想象的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 Places 返回地址信息以自动填充表单。
因此,Rails 应用程序中有一个部分正在加载到页面中。这意味着 DOM 已经创建,如果我们在初始页面加载时调用上面的函数(在 ajax 调用渲染部分之前),jQuery 将看不到 $('#property_street_address_1') 元素(相信我 - 它没有' t)。
因此我们需要延迟 google.maps.places.Autocomplete() 直到元素出现在页面上。
我们可以通过成功加载部分的 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() 相同的事情
为什么?因为函数声明是邪恶的。看看这段代码
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
现在以下将打印“true”:
foo = defineFct('foo', ()->'foo')
console.log(foo() == foo.name)
我实际上并没有使用这个,但有时确实希望咖啡函数有用于内省的名称。