Объявление функции в CoffeeScript - PullRequest
78 голосов
/ 01 июля 2011

Я заметил, что в CoffeeScript, если я определяю функцию, используя:

a = (c) -> c=1

Я могу получить только выражение функции :

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

Но лично я часто использую объявление функции , например:

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

Я использую первую форму, но мне интересно, есть ли способ в CoffeeScript генерировать объявление функции. Если такого способа нет, я хотел бы знать, почему CoffeeScript избегает этого. Я не думаю, что JSLint будет содержать ошибку для объявления, если функция объявлена ​​в верхней части области.

Ответы [ 7 ]

60 голосов
/ 01 июля 2011

CoffeeScript использует объявления функций (или именованные функции) только в одном месте: class определения. Например,

class Foo

компилируется в

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

Причина, по которой CoffeeScript не использует объявления функций в других местах, согласно FAQ :

Обвините Microsoft в этом. Первоначально каждой функции, для которой можно было получить разумное имя, было присвоено одно, но в IE версии 8 и ниже возникают проблемы с областями видимости, когда именованная функция рассматривается как объявление и выражение. См. это для получения дополнительной информации.

Вкратце: небрежное использование объявлений функций может привести к несоответствиям между IE (pre-9) и другими средами JS, поэтому CoffeeScript их избегает.

12 голосов
/ 25 марта 2014

Да, вы можете:

hello()

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

Вы избегаете чистого JS с помощью обратной черты `

Обратите внимание, что вы не можете сделать отступ для своего тела функции.

Приветствия

6 голосов
/ 27 октября 2013

При работе с 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 голос
/ 02 ноября 2015

Почему? Потому что объявление функции является злом. Посмотрите на этот код

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
1 голос
/ 09 октября 2014

Хотя это более старая запись, я хотел добавить кое-что в беседу для будущих пользователей Google.

OP верен в том смысле, что мы не можем объявлять функции в чистом CoffeeScript (исключая идею использования обратных тиков для экранирования чистого JS внутри файла CoffeeScript).

Но то, что мы можем сделать, это связать функцию с окном и по сути получить нечто, что мы можем вызвать, как если бы это была именованная функция. Я не утверждаю, что является именованной функцией, я предоставляю способ сделать то, что, как мне кажется, OP действительно хочет сделать (вызвать функцию, подобную foo (param) где-то в коде), используя чистый CoffeeScript.

Вот пример функции, прикрепленной к окну в 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') (поверьте мне - он не сделал) т).

Поэтому нам нужно отложить 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 голос
/ 13 октября 2011

Нет, вы не можете определить функцию в сценарии кофе и заставить ее генерировать объявление функции в сценарии кофе

Даже если вы просто напишите

-> 123

сгенерированный JS будет заключен в скобки, что делает его функциональным выражением

(function() {
  return 123;
});

Я предполагаю, что это потому, что объявления функций «поднимаются» в верхнюю часть области видимости, что нарушает логический поток исходного кода coffeescript.

0 голосов
/ 21 октября 2014

Попробуйте это:

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)

Я на самом деле не использую это, но иногда хочу, чтобы у функций кофе были имена для самоанализа.

...