Оголошення функції в CoffeeScript


79

Я помічаю, що в CoffeeScript, якщо я визначаю функцію, використовуючи:

a = (c) -> c=1

Я можу отримати лише вираз функції :

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

Але, особисто я часто використовую оголошення функції , наприклад:

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

Я використовую першу форму, але мені цікаво, чи існує спосіб у CoffeeScript генерувати декларацію функції. Якщо такого способу немає, я хотів би знати, чому CoffeeScript уникає цього. Я не думаю, що JSLint буде кричати помилку для оголошення, поки функція оголошена у верхній частині області.


4
Чи є у вас поважна причина вимагати оголошення функції? Якщо ви використовуєте coffeescript, вам не слід піклуватися про формат складеного JS, якщо він не зламаний / помилковий.
Raynos

3
У більшості випадків декларація функції та вираз функції працюють однаково, але між ними є невелика різниця. Наприклад, developer.mozilla.org/en/JavaScript/Reference/… Отже, у деяких випадках вони не рівні.
Грейс Шао,

Ви прив'язали мене до шматка коду, де оголошення функції - невизначена поведінка. Ви хочете використовувати декларації функцій замість виразів функцій, щоб ви могли зловживати невизначеною поведінкою?
Raynos

5
Оголошення функції @Raynos можуть бути приємними для трасування стека та інших налагоджень, оскільки до функції додається ім'я. Ось чому CoffeeScript використовує їх для classes.
Тревор Бернем

2
@TrevorBurnham Я мав на увазі, що це лише незначне поліпшення складності налагодження скомпільованого js. Насправді вам потрібен налагоджувач, який може читати coffeescript.
Raynos

Відповіді:


61

CoffeeScript використовує декларації функцій (вони ж "іменовані функції") лише в одному місці: classвизначення. Наприклад,

class Foo

компілює до

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

Причина, по якій CoffeeScript не використовує декларації функцій деінде, відповідно до поширених запитань :

Звинувачуйте Microsoft за це. Спочатку кожна функція, яка могла мати розумне ім'я, отримане для неї, отримувала одне, але версії IE 8 і старіші мають проблеми з масштабуванням, коли названа функція трактується як декларація і як вираз. Дивіться це для отримання додаткової інформації.

Коротше кажучи: необережне використання оголошень функцій може призвести до невідповідностей між IE (до 9) та іншими середовищами JS, тому CoffeeScript уникає їх.


31
Він говорить про проблему IE з іменованими виразами функцій (наприклад var a = function a() {};). Декларації функцій (наприклад function a() {}) не мають таких невідповідностей між браузерами
AngusC

4
Для мене це мало б більше сенсу, якби спочатку не було божевільним використання CS у браузері. Одна справа - довіритись бібліотеці, яка обробляє DOM, щоб не відставати від змін браузера та застарілих версій, але коли мова йде про власне вихідний код, це як подвійна залежність. Уявіть, що ви мали справу зі застарілою базою коду через 10 років після того, як спільнота CS пересохла і перейшла до наступного явища make-it-more-rails-like-for-me. Коли все починає ламатись, і вам потрібно дізнатись, що застаріло, і з’ясувати, що виправити в синтаксичному аналізаторі CS.
Ерік Реппен

12

Так, ти можеш:

hello()

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

Ви уникнете чистого JS за допомогою зворотного удару `

Зверніть увагу, що ви не можете робити відступи на тілі своєї функції.

Ура


19
Це не означає, що це робиться в coffeescript - лише те, що coffeescript дозволяє перейти в javascript. Також це наааасти!
Містер Уайльд,

9
Визначення перед використанням є більш неприємними xD
Заїд Дагестані

1
Крім того, виявляється, що функції оголошень сильно оптимізовані в пізніших версіях v8.
James M. Lay

зверніть увагу, що ви можете писати function updateSettings() {; do -> dothings (), }щоб дозволити відступ. github.com/jashkenas/coffeescript/issues / ...
avalanche1

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.


11
Піднімання - саме тому я хочу використовувати оголошення функцій!
ivanreese

1
CoffeeScript у певному сенсі вже "піднімається", оскільки він попередньо оголошує змінні з var у верхній частині області. Тож функції можуть посилатися одна на одну, і порядок не має значення.
Еван Моран,

15
@EvanMoran Це правда, що CoffeeScript попередньо оголошує змінні, але функції не піднімаються, оскільки змінна залишається невизначеною до виразу функції. Отже, ви не можете використовувати функції, поки вони не будуть визначені.
jasonkarns

1

Хоча це старіший пост, я хотів додати щось до розмови для майбутніх співробітників Google.

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

Але те, що ми можемо зробити, це прив’язати функцію до вікна і, по суті, отримати щось, що ми можемо викликати так, ніби це була названа функція. Я не про те , це є іменована функція, я забезпечую спосіб зробити те , що я вважаю , ОП хоче на насправді зробити (викликати функцію як Foo (пари) де - то в коді) з використанням чистого 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

Чому? Тому що оголошення функції є злом. Подивіться на цей код

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

8
У деклараціях функцій немає нічого поганого. Вам просто потрібно зрозуміти, як декларації змінних та функцій піднімаються в JS. Подальші читання про змінне піднімання та підйом функцій
Бен Гарольд,

визначення функції є більш інтимним, ніж оголошення функції.
Томаш Якуб Руп

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)

Я насправді цим не користуюся, але іноді хочу, щоб функції кави мали назви для самоаналізу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.