80

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

a = (c) -> c=1

我只能得到函数表达式

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

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

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

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

4

7 回答 7

61

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

class Foo

编译为

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

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

将此归咎于微软。最初,每个可以为其检索到合理名称的函数都被赋予了一个,但 IE 8 及以下版本存在范围问题,其中命名函数被视为声明和表达式。有关更多信息,请参阅

简而言之:粗心地使用函数声明会导致 IE(9 之前)和其他 JS 环境之间的不一致,因此 CoffeeScript 避开了它们。

于 2011-07-01T15:32:01.833 回答
12

是的你可以:

hello()

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

您通过反引号 ` 转义纯 JS

请注意,您不能在函数体上缩进。

干杯

于 2014-03-25T00:38:02.730 回答
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); }`
于 2013-10-27T18:47:51.033 回答
1

While this is an older post, I wanted to add something to the conversation for future Googlers.

OP is correct in that we cannot declare functions in pure CoffeeScript (excluding the idea of using back-ticks to escape pure JS inside the CoffeeScript file).

But what we can do is bind the function to the window and essentially end up with something we can call as though it was a named function. I am not stating this is a named function, I'm providing a way to do what I imagine OP wants to actually do (call a function like foo(param) somewhere in the code) using pure CoffeeScript.

Here is an example of a function attached to the window in 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

This is using Google Places to return address information to auto-populate a form.

So we have a partial in a Rails app which is being loaded into a page. This means the DOM is already created, and if we call the function above on initial page load (before the ajax call renders the partial), jQuery won't see the $('#property_street_address_1') element (trust me - it didn't).

So we need to delay the google.maps.places.Autocomplete() until after the element is present on the page.

We can do this via the Ajax callback on successful load of the partial:

            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

So here, essentially, we're doing the same thing as calling foo()

于 2014-10-09T16:34:48.187 回答
1

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

即使你只是写

-> 123

生成的 JS 将被包裹在括号中,从而使其成为函数表达式

(function() {
  return 123;
});

我的猜测是,这是因为函数声明被“提升”到封闭范围的顶部,这会破坏咖啡脚本源的逻辑流程。

于 2011-10-13T18:18:00.227 回答
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
于 2015-11-02T15:04:28.633 回答
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)

我实际上并没有使用它,但有时确实希望咖啡函数具有自省的名称。

于 2014-10-21T01:05:44.443 回答