CoffeeScript中的函数声明

时间:2011-07-01 13:42:22

标签: javascript coffeescript jslint function-declaration

我注意到在CoffeeScript中,如果我使用:

定义一个函数
a = (c) -> c=1

我只能获得函数表达式

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

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

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

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

7 个答案:

答案 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)

我实际上并没有使用它,但有时候希望咖啡功能有内省的名称。