Writing Your First Lines of CoffeeScript

0
74
8 min read

(For more resources related to this topic, see here.)

Following along with the examples

I implore you to open up a console as you read this article and try out the examples for yourself. You don’t strictly have to; I’ll show you any important output from the example code. However, following along will make you more comfortable with the command-line tools, give you a chance to write some CoffeeScript yourself, and most importantly, will give you an opportunity to experiment. Try changing the examples in small ways to see what happens. If you’re confused about a piece of code, playing around and looking at the outcome will often help you understand what’s really going on.

The easiest way to follow along is to simply open up a CoffeeScript console. Just run this from the command line to get an interactive console:

coffee

If you’d like to save all your code to return to later, or if you wish to work on something more complicated, you can create files instead and run those. Give your files the .coffee extension , and run them like this:

coffee my_sample_code.coffee

Seeing the compiled JavaScript

The golden rule of CoffeeScript, according to the CoffeeScript documentation, is:

It’s just JavaScript.

This means that it is a language that compiles down to JavaScript in a simple fashion, without any complicated extra moving parts. This also means that it’s easy, with a little practice, to understand how the CoffeeScript you are writing will compile into JavaScript. Your JavaScript expertise is still applicable, but you are freed from the tedious parts of the language. You should understand how the generated JavaScript will work, but you do not need to actually write the JavaScript.

To this end, we’ll spend a fair amount of time, especially in this article, comparing CoffeeScript code to the compiled JavaScript results. It’s like peeking behind the wizard’s curtain! The new language features won’t seem so intimidating once you know how they work, and you’ll find you have more trust in CoffeeScript when you can check in on the code it’s generating. After a while, you won’t even need to check in at all.

I’ll show you the corresponding JavaScript for most of the examples in this article, but if you write your own code, you may want to examine the output. This is a great way to experiment and learn more about the language! Unfortunately, if you’re using the CoffeeScript console to follow along, there isn’t a great way to see the compiled output (most of the time, it’s nice to have all that out of sight—just not right now!). You can see the compiled JavaScript in several other easy ways, though. The first is to put your code in a file and compile it. The other is to use the Try CoffeeScript tool on http://coffeescript.org/. It brings up an editor right in the browser that updates the output as you type.

CoffeeScript basics

Let’s get started! We’ll begin with something simple:

x = 1 + 1

You can probably guess what JavaScript this will compile to:

var x;
x = 1 + 1;

Statements

One of the very first things you will notice about CoffeeScript is that there are no semicolons. Statements are ended by a new line. The parser usually knows if a statement should be continued on the next line. You can explicitly tell it to continue to the next line by using a backslash at the end of the first line:

x = 1
+ 1

It’s also possible to stretch function calls across multiple lines, as is common in “fluent” JavaScript interfaces:

"foo"
.concat("barbaz")
.replace("foobar", "fubar")

You may occasionally wish to place more than one statement on a single line (for purely stylistic purposes). This is the one time when you will use a semicolon in CoffeeScript:

x = 1; y = 2

Both of these situations are fairly rare. The vast majority of the time, you’ll find that one statement per line works great. You might feel a pang of loss for your semicolons at first, but give it time. The calluses on your pinky finger will fall off, your eyes will adjust to the lack of clutter, and soon enough you won’t remember what good you ever saw in semicolons.

Variables

CoffeeScript variables look a lot like JavaScript variables, with one big difference: no var! CoffeeScript puts all variables in the local scope by default.

x = 1
y = 2
z = x + y

compiles to:

var x, y, z;
x = 1;
y = 2;
z = x + y;

Believe it or not, this is one of my absolute top favorite things about CoffeeScript. It’s so easy to accidentally introduce variables to the global scope in JavaScript and create subtle problems for yourself. You never need to worry about that again; from now on, it’s handled automatically. Nothing is getting into the global scope unless you want it there.

If you really want to put a variable in the global scope and you’re really sure it’s a good idea, you can easily do this by attaching it to the top-level object. In the CoffeeScript console, or in Node.js programs, this is the global object:

global.myGlobalVariable = "I'm so worldly!"

In a browser, we use the window object instead:

window.myGlobalVariable = "I'm so worldly!"

Comments

Any line that begins with a # is a comment. Anything after a # in the middle of a line will also be a comment.

# This is a comment.
"Hello" # This is also a comment

Most of the time, CoffeeScripters use only this style, even for multiline comments.

# Most multiline comments simply wrap to the
# next line, each begun with a # and a space.

It is also possible (but rare in the CoffeeScript world) to use a block comment, which begins and ends with ###. The lines in between these characters do not need to begin with a #.

###
This is a block comment. You can get artistic in here.
<(^^)>
###

Regular comments are not included in the compiled JavaScript, but block comments are, delineated by /* */.

Calling functions

Function invocation can look very familiar in CoffeeScript:

console.log("Hello, planet!")

Other than the missing semicolon, that’s exactly like JavaScript, right? But function invocation can also look different:

console.log "Hello, planet!"

Whoa! Now we’re in unfamiliar ground. This will work exactly the same as the previous example, though. Any time you call a function with arguments, the parentheses are optional. This also works with more than one argument:

Math.pow 2, 3

While you might be a little nervous writing this way at first, I encourage you to try it and give yourself time to become comfortable with it. Idiomatic CoffeeScript style eliminates parentheses whenever it’s sensible to do so. What do I mean by “sensible”? Well, imagine you’re reading your code for the first time, and ask yourself which style makes it easiest to comprehend. Usually it’s most readable without parentheses, but there are some occasions when your code is complex enough that judicious use of parentheses will help. Use your best judgment, and everything will turn out fine.

There is one exception to the optional parentheses rule. If you are invoking a function with no arguments, you must use parentheses:

Date.now()

Why? The reason is simple. CoffeeScript preserves JavaScript’s treatment of functions as first-class citizens.

myFunc = Date.now
#=> myFunc holds a function object that hasn't been executed
myDate = Date.now()
#=> myDate holds the result of the function's execution

CoffeeScript’s syntax is looser, but it must still be unambiguous. When no arguments are present, it’s not clear whether you want to access the function object or execute the function. Requiring parentheses makes it clear which one you want, and still allows both kinds of functionality. This is part of CoffeeScript’s philosophy of not deviating from the fundamentals of the JavaScript language. If functions were always executed instead of returned, CoffeeScript would no longer act like JavaScript, and it would be hard for you, the seasoned JavaScripter, to know what to expect. This way, once you understand a few simple concepts, you will know exactly what your code is doing.

From this discussion, we can extract a more general principle: parentheses are optional, except when necessary to avoid ambiguity . Here’s another situation in which you might encounter ambiguity: nested function calls.

Math.max 2, 3, Math.min 4, 5, 6

Yikes! What’s happening there? Well, you can easily clear this up by adding parentheses. You may add parentheses to all the function calls, or you may add just enough to resolve the ambiguity:

# These two calls are equivalent
Math.max(2, 3, Math.min(4, 5, 6))
Math.max 2, 3, Math.min(4, 5, 6)

This makes it clear that you wish min to take 4 and 5 as arguments. If you wished 6 to be an argument to max instead, you would place the parentheses differently.

# These two calls are equivalent
Math.max(2, 3, Math.min(4, 5), 6)
Math.max 2, 3, Math.min(4, 5), 6

Precedence

Actually, the original version I showed you is valid CoffeeScript too! You just need to understand the precedence rules that CoffeeScript uses for functions. Arguments are assigned to functions from the inside out . Another way to think of this is that an argument belongs to the function that it’s nearest to. So our original example is equivalent to the first variation we used, in which 4, 5, and 6 are arguments to min:

# These two calls are equivalent
Math.max 2, 3, Math.min 4, 5, 6
Math.max 2, 3, Math.min(4, 5, 6)

The parentheses are only absolutely necessary if our desired behavior doesn’t match CoffeeScript’s precedence—in this case, if we wanted 6 to be a argument to max. This applies to an unlimited level of nesting:

threeSquared = Math.pow 3, Math.floor Math.min 4, Math.sqrt 5

Of course, at some point the elimination of parentheses turns from the question of if you can to if you should. You are now a master of the intricacies of CoffeeScript function-call parsing, but the other programmers reading your code might not be (and even if they are, they might prefer not to puzzle out what your code is doing). Avoid parentheses in simple cases, and use them judiciously in the more complicated situations.

LEAVE A REPLY

Please enter your comment!
Please enter your name here