CoffeeScript 中的函数声明

问题描述 投票:0回答:7

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

a = (c) -> c=1

我只能得到函数表达式:

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

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

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

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

javascript coffeescript
7个回答
61
投票

CoffeeScript 仅在一处使用函数声明(又名“命名函数”):

class
定义。例如,

class Foo

编译为

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

根据 FAQ,CoffeeScript 不在其他地方使用函数声明的原因:

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

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


12
投票

是的,你可以:

hello()

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

你可以通过反引号 `

来转义纯 JS

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

干杯


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); }`

1
投票

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

即使你只是写

-> 123

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

(function() {
  return 123;
});

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


1
投票

虽然这是一篇较旧的帖子,但我想为未来的 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() 相同的事情


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

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)

我实际上并没有使用这个,但有时确实希望咖啡函数有用于内省的名称。

© www.soinside.com 2019 - 2024. All rights reserved.