For this blog post we’re going to continue where we previously left off, talking a bit more about functions in CoffeeScript. Let’s get things started by talking a bit about function scope.
Function scope
Like Ruby, CoffeeScript uses lexical scope. This means that a variable that is declared inside a function is invisible to outside code. From there on, a variable lives inside the scope in which a value is assigned to it without being able to be redeclared. Because we don't have access to the var keyword, we can't simply declare a variable and use it in a different scope without assigning a value to it.
Consider the following code:
The output might come as a surprise to you, but it actually makes a lot of sense. A variable that is declared inside an inner scope cannot shadow a variable with the same name that is declared in an outer scope. I highly recommend that you avoid reusing variable names as shown by this example.
Function context
In JavaScript, the this keyword inside a function does not necessarily point to the object for which the function is declared. The object that is referenced by this depends on how the function is called. The same applies to CoffeeScript as well, only it uses the '@' symbol for denoting the this keyword in JavaScript. Let’s look at a couple of scenarios.
Compiling this down to JavaScript results in the following code:
As you can see, @podcast is the shorthand notation for this.podcast in JavaScript. For this example, this references the global object. Let’s have a look at another scenario.
This results in the following JavaScript code:
When calling a constructor function using the new operator, this references the new object being created. We've also explicitly added 'return @' in order to return the new object. Otherwise the function assigned to the download property is implicitly returned. Let’s move on to the next case.
Compiling this to JavaScript results into the following code:
As I already mentioned in a previous blog post, we can reuse methods from other objects using the call()/apply() methods defined on the prototype of Function. In this example we reuse the download function in the context of the otherPodcast object. This means that this now references otherPodcast instead of the podcast object. Let’s dive into the final and most common scenario.
The equivalent JavaScript code looks like this:
Here this simply references the current object to which the executing function belongs to.
Function binding
Going over these different scenarios regarding the function context, it might be useful to be able to define a function that binds to the current value of this. In CoffeeScript we can use the => symbol instead of –> to accomplish just that. Let’s look at the code example from the CoffeeScript website.
This is especially helpful for event callbacks. The reason you might want to consider the ‘fat arrow’ in this case is that callbacks are executed in the context of the element, i.e. this references the element. When you want to keep this equal to the local context, without doing the self = this dance, then ‘fat arrows’ are the way to go.
Splats
Splats enable us to easily take a variable number of parameters in a function. JavaScript has a similar construct with the arguments object that is available in every function. But the major downside of the arguments object is that it lacks the semantics of an array which makes it pretty cumbersome to use. With splats, CoffeeScript provides us with a much better way to deal with a varying number of parameters.
This boils down to the following (nasty) JavaScript code:
As you can see, splats don't have to be defined at the end of the parameter list. For this example, the first and last value get to be assigned to the regular parameters after which the remaining values in the middle of the list get assigned to the splat parameter. When we only specify two values, then these will be used for the regular parameters while the splat parameter will be null.
The values for the regular parameters get to be assigned first after which the remaining values all get to be passed to the splat parameter. This also implies that there can be only a single splat parameter for a given function definition.
Splats are not only available for function definitions, but also for calling functions as well.
This simply boils down to calling the apply() method of the download function in the resulting JavaScript code:
someFunction = -> podcast = 'Hardcore history'
podcast = 'Astronomy cast'
someFunction()
console.log podcast # This outputs 'Astronomy cast'
No doubt that CoffeeScript brings a lot of goodness to the table when it comes to functions. But there’s also a lot more. Stay tuned for the next couple of blog posts.
Until next time.