Объявление функции в CoffeeScript
Я замечаю, что в CoffeeScript, если я определяю функцию, используя:
a = (c) -> c=1
Я могу получить только выражение функции :
var a;
a = function(c) {
return c = 1;
};
Но лично я часто использую объявление функции, например:
function a(c) {
return c = 1;
}
Я использую первую форму, но мне интересно, есть ли способ в CoffeeScript генерировать объявление функции. Если такого пути нет, я хотел бы знать, почему CoffeeScript избегает этого. Я не думаю, что JSLint будет вызывать ошибку для объявления, если функция объявлена в верхней части области.
Ответы
Ответ 1
CoffeeScript использует объявления функций (так называемые именованные функции) только в одном месте: class
определения. Например,
class Foo
компилируется в
var Foo;
Foo = (function() {
function Foo() {}
return Foo;
})();
Причина, по которой CoffeeScript не использует объявления функций в другом месте, в соответствии с FAQ:
Поручите Microsoft для этого. Первоначально каждая функция, которая могла иметь разумное имя, полученную для нее, была дана одна, но IE версии 8 и ниже имеют проблемы определения области, где именованная функция рассматривается как декларация и выражение. Подробнее см. .
Вкратце: использование деклараций функций небрежно может привести к несогласованности между IE (pre-9) и другими средами JS, поэтому CoffeeScript избегает их.
Ответ 2
Да, вы можете:
hello()
`function hello() {`
console.log 'hello'
dothings()
`}`
Вы избегаете чистого JS через обратную сторону `
Обратите внимание, что вы не можете отступать от своего тела функции.
Приветствия
Ответ 3
Одна вещь, которая стоит иметь в виду с 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, а затем просто использовать трюк backticks, чтобы 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); }`
Ответ 4
Нет, вы не можете определить функцию в кофе script и заставить ее генерировать объявление функции в кофе script
Даже если вы просто пишете
-> 123
сгенерированный JS будет обернут в parens, что сделает его выражением функции
(function() {
return 123;
});
Мое предположение заключается в том, что это потому, что объявления функций "поднимаются" вверху охватывающей области, которая разрушает логический поток источника coffeescript.
Ответ 5
В то время как это более старая должность, я хотел добавить что-то в разговор для будущих Googlers.
OP верен тем, что мы не можем объявлять функции в чистом CoffeeScript (исключая идею использования back-ticks, чтобы избежать чистой 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 Адресов, чтобы возвращать адресную информацию для автоматического заполнения формы.
Итак, у нас есть частичное приложение Rails, которое загружается на страницу. Это означает, что DOM уже создан, и если мы вызываем функцию выше при начальной загрузке страницы (до того, как вызов ajax отображает частичный), jQuery не увидит элемент $('# property_street_address_1') (поверьте мне - он didn ' т).
Поэтому нам нужно задержать 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()
Ответ 6
Почему? Потому что объявление функции является злом. Посмотрите на этот код
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
Ответ 7
Попробуйте следующее:
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)
Я действительно не использую это, но иногда хочу, чтобы функции кофе имели имена для интроспекции.