Programming in CoffeeScript: Functions and Arguments
- Function Basics
- Arguments
- Default Arguments
- Splats...
- Wrapping Up
I wanted to give you an example of what JavaScript would look like if we were not able to use or write functions, but I was unable to. Even the simplest example of taking a string and making it lowercase requires the use of functions in JavaScript.
Since I can’t show you an example devoid of functions, let me show you an example of some CoffeeScript code that could use the help of a function or two, so you can see just how important functions are to helping you keep your code manageable.
Example: (source: no_functions_example.coffee)
tax_rate = 0.0625 val = 100 console.log "What is the total of $#{val} worth of shopping?" tax = val * tax_rate total = val + tax console.log "The total is #{total}" val = 200 console.log "What is the total of $#{val} worth of shopping?" tax = val * tax_rate total = val + tax console.log "The total is #{total}"
Example: (source: no_functions_example.js)
(function() { var tax, tax_rate, total, val; tax_rate = 0.0625; val = 100; console.log("What is the total of $" + val + " worth of shopping?"); tax = val * tax_rate; total = val + tax; console.log("The total is " + total); val = 200; console.log("What is the total of $" + val + " worth of shopping?"); tax = val * tax_rate; total = val + tax; console.log("The total is " + total); }).call(this);
Output: (source: no_functions_example.coffee)
What is the total of $100 worth of shopping? The total is 106.25 What is the total of $200 worth of shopping? The total is 212.5
In our example we are calculating the total value of goods purchased in state with certain sales tax. Apart from the banality of the example, you can see that we are repeating our code to calculate the total value with tax several times.
Let’s refactor our code a bit, add some functions, and try to clean it up.
Example: (source: with_functions_example.coffee)
default_tax_rate = 0.0625 calculateTotal = (sub_total, rate = default_tax_rate) -> tax = sub_total * rate sub_total + tax val = 100 console.log "What is the total of $#{val} worth of shopping?" console.log "The total is #{calculateTotal(val)}" val = 200 console.log "What is the total of $#{val} worth of shopping?" console.log "The total is #{calculateTotal(val)}"
Example: (source: with_functions_example.js)
(function() { var calculateTotal, default_tax_rate, val; default_tax_rate = 0.0625; calculateTotal = function(sub_total, rate) { var tax; if (rate == null) rate = default_tax_rate; tax = sub_total * rate; return sub_total + tax; }; val = 100; console.log("What is the total of $" + val + " worth of shopping?"); console.log("The total is " + (calculateTotal(val))); val = 200; console.log("What is the total of $" + val + " worth of shopping?"); console.log("The total is " + (calculateTotal(val))); }).call(this);
Output: (source: with_functions_example.coffee)
What is the total of $100 worth of shopping? The total is 106.25 What is the total of $200 worth of shopping? The total is 212.5
Now, I know you probably don’t understand everything we just did there. Don’t worry, that’s what this chapter is for, but even without knowing the specifics of how functions are defined, and work, in CoffeeScript, you can see how much cleaner our code is between the two examples. In the refactored code we are even able to pass in a different tax rate, should we need to. This also helps us keep our code DRY1: “Don’t Repeat Yourself”. No repeating your code makes for an easier to manage code base with, hopefully, fewer bugs.
So, enough yakking about how great functions are; let’s start learning about how they work in CoffeeScript!
Function Basics
Let’s start with the very basics on how to define a function in CoffeeScript. The anatomy of a very simple function looks like this:
Example: (source: simple_function.coffee)
myFunction = ()-> console.log "do some work here" myFunction()
Example: (source: simple_function.js)
(function() { var myFunction; myFunction = function() { return console.log("do some work here"); }; myFunction(); }).call(this);
In that example we gave the function a name, myFunction, and a code block to go with it. The body of the function is the code that is indented below the ->, following the significant whitespace rules we learned about in Chapter 2, “The Basics”.
The function does not accept any arguments. We know that by the empty parentheses prior to the ->. When calling a function in CoffeeScript that has no arguments we are required to use parentheses, myFunction().
Since our function has no arguments we can drop the parentheses all together when defining it, like so:
Example: (source: simple_function_no_parens.coffee)
myFunction = -> console.log "do some work here" myFunction()
Example: (source: simple_function_no_parens.js)
(function() { var myFunction; myFunction = function() { return console.log("do some work here"); }; myFunction(); }).call(this);
There is one more way we can write this simple function. Because the body of our function is only on one line we can collapse the whole function definition down to one like:
Example: (source: simple_function_one_line.coffee)
myFunction = -> console.log "do some work here" myFunction()
Example: (source: simple_function_one_line.js)
(function() { var myFunction; myFunction = function() { return console.log("do some work here"); }; myFunction(); }).call(this);
All three of the previous code examples all produce the exact same JavaScript and are called in the same exact way.
You should also notice that the last line of each function contains a return keyword. CoffeeScript adds this automatically for you. Whatever the last line of your function is that will be the function’s return value. This is similar to languages such as Ruby. Because CoffeeScript will automatically add the return for you in the compiled JavaScript the use of the return keyword in your CoffeeScript is optional.