Function declaration in CoffeeScript

JavascriptCoffeescriptJslintFunction Declaration

Javascript Problem Overview


I notice that in CoffeeScript, if I define a function using:

a = (c) -> c=1

I can only get the function expression:

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

But, personally I often use function declaration,for example:

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

I do use the first form, but I'm wondering if there is a way in CoffeeScript generating a function declaration. If there is no such way, I would like to know why CoffeeScript avoid doing this. I don't think JSLint would holler an error for declaration, as long as the function is declared at the top of the scope.

Javascript Solutions


Solution 1 - Javascript

CoffeeScript uses function declarations (aka "named functions") in just one place: class definitions. For instance,

class Foo

compiles to

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

The reason CoffeeScript doesn't use function declarations elsewhere, according to the FAQ:

> Blame Microsoft for this one. Originally every function that could have a sensible name retrieved for it was given one, but IE versions 8 and down have scoping issues where the named function is treated as both a declaration and an expression. See this for more information.

In short: Using function declarations carelessly can lead to inconsistencies between IE (pre-9) and other JS environments, so CoffeeScript eschews them.

Solution 2 - Javascript

Yes you can:

hello()

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

You escape pure JS via the backtick `

Note that you can't indent on your function body.

Cheers

Solution 3 - Javascript

One thing to keep in mind with CoffeeScript is that you can always kick back to JavaScript. While CoffeeScript doesn't support named function declarations, you can always drop back to JavaScript to do it.

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

You can also write a big fat function in CoffeeScript and then just use the backticks trick to have JavaScript call the other function:

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

Solution 4 - Javascript

No, you can't define a function in coffee script and have it generate a function declaration in coffee script

Even if you just write

-> 123

the generated JS will be wrapped in parens, thus making it a function expression

(function() {
  return 123;
});

My guess is that this is because function declarations get "hoisted" to the top of the enclosing scope which would break up the logical flow of the coffeescript source.

Solution 5 - Javascript

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()

Solution 6 - Javascript

Why? Because function declaration is evil. Look at this code

function a() {
        return 'a';
}

console.log(a());

function a() {
        return 'b';
}

console.log(a());

What will be on the output?

b
b

If we use the function definition

var a = function() {
        return 'a';
}

console.log(a());

a = function() {
        return 'b';
}

console.log(a());

the output is:

a
b

Solution 7 - Javascript

Try this:

defineFct = (name, fct)->
  eval("var x = function #{name}() { return fct.call(this, arguments); }")
  return x

Now the following will print "true":

foo = defineFct('foo', ()->'foo')
console.log(foo() == foo.name)

I don't actually use this, but do sometimes wish coffee functions had names for introspection.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGrace ShaoView Question on Stackoverflow
Solution 1 - JavascriptTrevor BurnhamView Answer on Stackoverflow
Solution 2 - JavascriptZaid DaghestaniView Answer on Stackoverflow
Solution 3 - Javascriptmattmc3View Answer on Stackoverflow
Solution 4 - JavascriptAngusCView Answer on Stackoverflow
Solution 5 - JavascriptnotaceoView Answer on Stackoverflow
Solution 6 - JavascriptTomasz Jakub RupView Answer on Stackoverflow
Solution 7 - JavascriptshauncView Answer on Stackoverflow