3. Control Structures

Almost all languages have the concept of operators1 and conditionals;2 JavaScript and CoffeeScript are no different. Operators and conditionals work hand in hand to form an important part of all programming languages. Operators let you do things such as add or subtract two numbers, compare two objects, shift bytes in an object, and so on. Conditionals, on the other hand, let us control the flow of our application based on certain predefined conditions. For example if a user is not logged in then send them to the login screen, else show them the secret page. That is a conditional statement.

In this chapter we take a look at both operators and conditionals and how they are defined in CoffeeScript.

Operators and Aliases

For the most part, JavaScript and CoffeeScript play nicely in terms of the operators behaving the same. However, in a few places CoffeeScript steps in to help make sure you don’t step on some land mines that JavaScript has lurking about its innards. To make sure we understand fully what all the operators do, let’s take a quick tour of the JavaScript operators, and I’ll point out when they are different from their CoffeeScript counterparts. Before we continue, I want to say that I am assuming you know what all the JavaScript operators do. If you don’t, now is a good time to brush up on them. If you need a reference, I recommend http://en.wikibooks.org/wiki/JavaScript/Operators. It offers a quick, but well written, overview of the operators available in JavaScript.

Arithmetic

Here is a list of each of the arithmetic operators in JavaScript:

+ Addition

- Subtraction

* Multiplication

/ Division (returns a floating-point value)

% Modulus (returns the integer remainder)

+ Unary conversion of string to number

- Unary negation (reverses the sign)

++ Increment (can be prefix or postfix)

-- Decrement (can be prefix or postfix)

Now let’s take a look at how those operators translate in the CoffeeScript world:

Example: (source: arithmetic.coffee)


console.log "+ Addition: #{1 + 1}"

console.log "- Subtraction: #{10 - 1}"

console.log "* Multiplication: #{5 * 5}"

console.log "/ Division: #{100 / 10}"

console.log "% Modulus: #{10 % 3}"

console.log "+ Unary conversion of string to number: #{+'100'}"

console.log "- Unary negation: #{-50}"

i = 1
x = ++i
console.log "++ Increment: #{x}"

i = 1
x = --i
console.log "-- Decrement: #{x}"


Example: (source: arithmetic.js)


(function() {
  var i, x;

  console.log("+ Addition: " + (1 + 1));

  console.log("- Subtraction: " + (10 - 1));

  console.log("* Multiplication: " + (5 * 5));

  console.log("/ Division: " + (100 / 10));

  console.log("% Modulus: " + (10 % 3));

  console.log("+ Unary conversion of string to number: " + (+'100'));

  console.log("- Unary negation: " + (-50));

  i = 1;

  x = ++i;

  console.log("++ Increment: " + x);

  i = 1;

  x = --i;

  console.log("-- Decrement: " + x);

}).call(this);


Output: (source: arithmetic.coffee)


+ Addition: 2
- Subtraction: 9
* Multiplication: 25
/ Division: 10
% Modulus: 1
+ Unary conversion of string to number: 100
- Unary negation: -50
++ Increment: 2
-- Decrement: 0


As we can see from the example, all our CoffeeScript arithmetic operators map directly to JavaScript, so we won’t be losing any sleep at night trying to remember them.

Assignment

Now we’ll move on to the assignment operators in JavaScript, which are presented in the following list:

= Assign

+= Add and assign

-= Subtract and assign

*= Multiply and assign

/= Divide and assign

%= Modulus and assign

?= Exists or assign

||= Or or assign

&&= Assign if both are true

How do they map to CoffeeScript?

Example: (source: assignment.coffee)


console.log "= Assign:"
x = 10
console.log x

console.log "+= Add and assign:"
x += 25
console.log x

console.log "-= Subtract and assign:"
x -= 25
console.log x

console.log "*= Multiply and assign:"
x *= 10
console.log x

console.log "/= Divide and assign:"
x /= 10
console.log x

console.log "%= Modulus and assign:"
x %= 3
console.log x

console.log "?= Exists or assign:"
y ?= 3
console.log y
y ?= 100
console.log y

console.log "||= Or or assign:"
z = null
z ||= 10
console.log z
z ||= 100
console.log z

console.log "&&= Assign if both are true:"
a = 1
b = 2
console.log a &&= b
console.log a


Example: (source: assignment.js)


(function() {
  var a, b, x, z;

  console.log("= Assign:");

  x = 10;

  console.log(x);

  console.log("+= Add and assign:");

  x += 25;

  console.log(x);

  console.log("-= Subtract and assign:");

  x -= 25;

  console.log(x);

  console.log("*= Multiply and assign:");

  x *= 10;

  console.log(x);

  console.log("/= Divide and assign:");

  x /= 10;

  console.log(x);

  console.log("%= Modulus and assign:");

  x %= 3;

  console.log(x);

  console.log("?= Exists or assign:");

  if (typeof y === "undefined" || y === null) y = 3;

  console.log(y);

  if (typeof y === "undefined" || y === null) y = 100;

  console.log(y);

  console.log("||= Or or assign:");

  z = null;

  z || (z = 10);

  console.log(z);

  z || (z = 100);

  console.log(z);

  console.log("&&= Assign if both are true:");

  a = 1;

  b = 2;

  console.log(a && (a = b));

  console.log(a);

}).call(this);


Output: (source: assignment.coffee)


= Assign:
10
+= Add and assign:
35
-= Subtract and assign:
10
*= Multiply and assign:
100
/= Divide and assign:
10
%= Modulus and assign:
1
?= Exists or assign:
3
3
||= Or or assign:
10
10
&&= Assign if both are true:
2
2


Again, all the operators map directly. Isn’t life wonderful?

Comparison

Now let’s take a look at the comparison operators and see how they map between CoffeeScript and JavaScript.

== Equal

!= Not equal

> Greater than

>= Greater than or equal to

< Less than

<= Less than or equal to

=== Identical (equal and of the same type)

!== Not identical

Okay, let’s take a peek and see how these operators behave in CoffeeScript:

Example: (source: comparison.coffee)


console.log "== Equal: #{1 == 1}"

console.log "!= Not equal: #{1 != 2}"

console.log "> Greater than: #{2 > 1}"

console.log ">= Greater than or equal to: #{1 >= 1}"

console.log "< Less than: #{1 < 2}"

console.log "<= Less than or equal to: #{1 < 2}"

console.log "=== Identical: #{'a' === 'a'}"

console.log "!== Not identical: #{1 !== 2}"


Output: (source: comparison.coffee)


Error: In content/control_structures/comparison.coffee, Parse error on line 13: Unexpected '='
    at Object.parseError (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/parser.js:470:11)
    at Object.parse (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/parser.js:546:22)
    at /usr/local/lib/node_modules/coffee-script/lib/coffee-script/coffee-script.js:40:22
    at Object.run /usr/local/lib/node_modules/coffee-script/lib/coffee-script/coffee-script.js:68:34)
    at /usr/local/lib/node_modules/coffee-script/lib/coffee-script/command.js:135:29
    at /usr/local/lib/node_modules/coffee-script/lib/coffee-script/command.js:110:18
    at [object Object].<anonymous> (fs.js:114:5)
    at [object Object].emit (events.js:64:17)
    at afterRead (fs.js:1081:12)
    at Object.wrapper [as oncomplete] (fs.js:252:17)


Well, that doesn’t look right, does it? Let’s look at what happened there and why our example blew up. CoffeeScript does not allow the use of the === or !== operators. Hopefully, by the time this book goes to print a better error message will be presented that is both clearer and more informative. I can hear everyone crying out in horror because those are the comparison operators we should be using the most, but don’t worry, CoffeeScript does have our backs here. Let me explain.

Let’s rebuild our example code; this time we’ll drop our === and !== examples:

Example: (source: comparison2.coffee)


console.log "== Equal: #{1 == 1}"

console.log "!= Not equal: #{1 != 2}"

console.log "> Greater than: #{2 > 1}"

console.log ">= Greater than or equal to: #{1 >= 1}"

console.log "< Less than: #{1 < 2}"

console.log "<= Less than or equal to: #{1 < 2}"


Example: (source: comparison2.js)


(function() {

  console.log("== Equal: " + (1 === 1));

  console.log("!= Not equal: " + (1 !== 2));

  console.log("> Greater than: " + (2 > 1));

  console.log(">= Greater than or equal to: " + (1 >= 1));

  console.log("< Less than: " + (1 < 2));

  console.log("<= Less than or equal to: " + (1 < 2));

}).call(this);


Output: (source: comparison2.coffee)


== Equal: true
!= Not equal: true
> Greater than: true
>= Greater than or equal to: true
< Less than: true
<= Less than or equal to: true


Great! Our examples didn’t blow up this time, but you should’ve noticed something very interesting. Did you see how our == and != examples converted when compiled in JavaScript? CoffeeScript compiled those examples into === and !== respectively. Why did CoffeeScript do that? Let’s look at what happens in JavaScript when you use == and !=:

Example: (source: javascript_comparison.js)


x = 1;
y = '1';
console.log(x == y); // true


In the JavaScript example, 1 is equal to "1" despite the fact that they are different objects. The reason is that when using the == comparison operator in JavaScript it will automatically coerce the two objects to the same type of object and then do the comparison on it. The same holds true for the != operator. This is the source of a great many JavaScript bugs. To get a true comparison of two objects you must use the === operator.

If we look at the same example again, only this time using the === operator, you see that we get false for our comparison instead of true:

Example: (source: javascript_comparison2.js)


x = 1;
y = '1';
console.log(x === y); // false


To make sure you don’t run into these sorts of bugs, CoffeeScript automatically converts any == and != operators into === and !== for you. Isn’t that nice? CoffeeScript is helping you keep your bugs to a minimum. You should send it a thank you card. There is another way to use the === and !== operators, which we’ll look at in a minute when we discuss aliases.

String

Finally, there are a few operators that work on strings.

+ Concatenation

+= Concatenate and assign

Here they are in CoffeeScript:

Example: (source: string_operators.coffee)


console.log "+ Concatenation: #{'a' + 'b'}"

x = 'Hello'
x += " World"
console.log "+= Concatenate and assign: #{x}"


Example: (source: string_operators.js)


(function() {
  var x;

  console.log("+ Concatenation: " + ('a' + 'b'));

  x = 'Hello';

  x += " World";

  console.log("+= Concatenate and assign: " + x);

}).call(this);


Output: (source: string_operators.coffee)


+ Concatenation: ab
+= Concatenate and assign: Hello World


Fortunately, these operators work just like they do in JavaScript.

The Existential Operator

When I first discovered CoffeeScript, I immediately fell in love with the existential operator. This operator lets you check, well, the existence of a variable or function, using a simple ?.

Let’s take a quick look:

Example: (source: existential1.coffee)


console.log x?


Example: (source: existential1.js)


(function() {

  console.log(typeof x !== "undefined" && x !== null);

}).call(this);


Output: (source: existential1.coffee)


false


As you can see in our example, CoffeeScript generates JavaScript that checks to see if the variable x is defined; if it is, then it checks to see if it is not null. This can make writing conditionals very powerful.

Example: (source: existential_if.coffee)


if html?
  console.log html


Example: (source: existential_if.js)


(function() {

  if (typeof html !== "undefined" && html !== null) console.log(html);

}).call(this);


The fun doesn’t stop there with the existential operator. Using the existential operator, we can check the existence of something, and if it exists, call a function on it. My favorite example of this is with the console object. For those of you unfamiliar with the console object, it exists in most browsers as a way to write messages to the built-in JavaScript error console. Typically, this is used by developers as a way of logging messages at certain points in the code for either debugging or informational purposes. I’ve been using it in almost all the book examples as a way to demonstrate the output of our examples.

The problem with the console object is that it isn’t always there (Internet Explorer, I’m looking at you!). If you attempt to call a function or call a property on a variable that doesn’t exist, the browser will raise an exception and your program will not execute properly. The existential operator can help us get around the problem of calling functions on objects that are not defined, such as the console object in certain browsers.

First, let’s look at an example where we don’t use the existential operator:

Example: (source: existential2.coffee)


console.log "Hello, World"
console.log someObject.someFunction()
console.log "Goodbye, World"


Example: (source: existential2.js)


(function() {

  console.log("Hello, World");

  console.log(someObject.someFunction());

  console.log("Goodbye, World");

}).call(this);


Output: (source: existential2.coffee)


Hello, World
ReferenceError: someObject is not defined
    at Object.<anonymous> (.../control_structures/existential2.coffee:5:15)
    at Object.<anonymous> (.../control_structures/existential2.coffee:9:4)
    at Module._compile (module.js:432:26)
    at Object.run (/usr/local/lib/node_modules/coffee-script/lib/coffee-script/coffee-script.js:68:25)
    at /usr/local/lib/node_modules/coffee-script/lib/coffee-script/command.js:135:29
    at /usr/local/lib/node_modules/coffee-script/lib/coffee-script/command.js:110:18
    at [object Object].<anonymous> (fs.js:114:5)
    at [object Object].emit (events.js:64:17)
    at afterRead (fs.js:1081:12)
    at Object.wrapper [as oncomplete] (fs.js:252:17)


Well, that’s a nasty little error, isn’t it? Our example is blowing up because it cannot find an object named someObject and we are attempting to call a function. Now, if we add the existential operator after someObject, let’s see what happens.

Example: (source: existential3.coffee)


console.log "Hello, World"
console.log someObject?.someFunction()
console.log "Goodbye, World"


Example: (source: existential3.js)


(function() {

  console.log("Hello, World");

  console.log(typeof someObject !== "undefined" && someObject !== null ? someObject.someFunction() : void 0);

  console.log("Goodbye, World");

}).call(this);


Output: (source: existential3.coffee)


Hello, World
undefined
Goodbye, World


That is definitely better. Although we got an undefined message when we tried to access our someObject variable, the program did fully execute. If this were a real-world example, we might want to log a message or possibly raise some sort of alert, but for now I think we’ve done our part to make our code a little safer.

Aliases

In an effort to make your code a little more user friendly, CoffeeScript has added a few aliases for some of the more common operators. Some of these aliases make wonderful additions to the language, but others are a little confusing. Table 3.1 shows the CoffeeScript aliases and their JavaScript counterparts.

Table 3.1 CoffeeScript Aliases and Their JavaScript Counterparts

Image

Let’s take a look at all but the last two aliases. The last two aliases will be covered in Chapter 5, “Collections and Iterations.”

The is and isnt Aliases

Here is an example of the is, isnt operator aliases in action:

Example: (source: is_aliases.coffee)


name = "mark"

console.log name is "mark"
console.log name isnt "bob"


Example: (source: is_aliases.js)


(function() {
  var name;

  name = "mark";

  console.log(name === "mark");

  console.log(name !== "bob");

}).call(this);


Output: (source: is_aliases.coffee)


true
true


As you can see, in our code the is alias mapped to the === and the isnt operator mapped to the !==. As you recall from our earlier discussions in this chapter, the === and !== operators are the comparison operators CoffeeScript not only wants you to use, but insists you use. CoffeeScript also would prefer you to use the is and isnt aliases. They are considered “the CoffeeScript way.” Removing the == and != as legal operators from CoffeeScript and forcing the use of the is and isnt operators only has been discussed. As of the time of this writing this has not happened, but it is something you should be aware of. This particular caveat holds true of all the aliases and their appropriate matching operator.

The not Alias

The not alias and I have a love/hate relationship. I love the way it makes my code look, but I hate the way it doesn’t always behave the way I want it to. The idea of the not alias is the same as the ! operator in JavaScript; it will “flip” the Boolean state of a variable. That means it will make a true become false and vice versa.

Let’s take a look at how the not alias behaves:

Example: (source: not_alias.coffee)


userExists = false

if not userExists
  console.log "the user doesn't exist!"


Example: (source: not_alias.js)


(function() {
  var userExists;

  userExists = false;

  if (!userExists) console.log("the user doesn't exist!");

}).call(this);


Output: (source: not_alias.coffee)


the user doesn't exist!


As you can see, we have to make sure to place a space between the not alias and the variable we are trying to “flip” Boolean states on.

So how does this get confusing? In CoffeeScript it is possible to write this code:

Example: (source: not_alias_wrong.coffee)


name = "mark"

console.log name isnt "bob"
console.log name is not "bob"


Example: (source: not_alias_wrong.js)


(function() {
  var name;

  name = "mark";

  console.log(name !== "bob");

  console.log(name === !"bob");

}).call(this);


Output: (source: not_alias_wrong.coffee)


true
false


Although grammatically those couple of lines look correct, they are actually very different lines of code. The line using the isnt alias is checking that the two objects are not equal. The line using the is not alias is checking the equality of the first variable to the “flipped” Boolean value of the second. This is an easy mistake to make, especially when you are first starting with CoffeeScript.

The and and or Aliases

I love these aliases. The and and or aliases not only read well in your code, but they do just what you would expect them to do! Here’s an example:

Example: (source: and_or.coffee)


if true and true
  console.log "true and true really is true"

if false or true
  console.log "something was true"


Example: (source: and_or.js)


(function() {

  if (true && true) console.log("true and true really is true");

  if (false || true) console.log("something was true");

}).call(this);


Output: (source: and_or.coffee)


true and true really is true
something was true


Like I said, they do just what you would expect them to do.

The Boolean Aliases

CoffeeScript supports not just true and false for Booleans, but also took a page from the book of YAML3 and added a few other aliases to make your code nicer to read.

Let’s have a look:

Example: (source: boolean_operators.coffee)


myAnswer = true
console.log myAnswer is yes
console.log myAnswer is true

light = true
console.log light is on
console.log light is true

myAnswer = false
console.log myAnswer is no
console.log myAnswer is false

light = false
console.log light is off
console.log light is false


Example: (source: boolean_operators.js)


(function() {
  var light, myAnswer;

  myAnswer = true;

  console.log(myAnswer === true);

  console.log(myAnswer === true);

  light = true;

  console.log(light === true);

  console.log(light === true);

  myAnswer = false;

  console.log(myAnswer === false);

  console.log(myAnswer === false);

  light = false;

  console.log(light === false);

  console.log(light === false);

}).call(this);


Output: (source: boolean_operators.coffee)


true
true
true
true
true
true
true
true


As you can see the yes, no, on, and off aliases can make your code fun and easy to read.

The @ Alias

The last alias we look at before we move on is the @ alias. We will revisit this alias from time to time throughout the book as we talk about different areas of CoffeeScript. For now let’s talk about its most basic, and common, use: as an alias for the JavaScript keyword this.

Here is a very simple example of the @ alias at work:

Example: (source: at_alias.coffee)


object = {
  name: 'mark'
  sayHi: ->
    console.log "Hello: #{@name}"
}
object.sayHi()

console.log @name


Example: (source: at_alias.js)


(function() {
  var object;

  object = {
    name: 'mark',
    sayHi: function() {
      return console.log("Hello: " + this.name);
    }
  };

  object.sayHi();

  console.log(this.name);

}).call(this);


Output: (source: at_alias.coffee)


Hello: mark
undefined


If you don’t understand how this scoping in JavaScript works, or even what this is, I urge you to put this book down now and pick up a proper JavaScript book and read that first.

As you can see, if you compare our CoffeeScript example and its compiled JavaScript output, all references to @ were replaced with this. when compiled. I find that my code is much easier to read when using the @ symbol. I can easily distinguish between “local” variables, sometimes referred to as instance variables, within a function and variables and functions that are defined outside of the current function I’m working in.

If/Unless

In my travels as a developer, I have yet to meet a programming language that didn’t have the concept of conditional statements. I’m sure somebody out there has written one, but I doubt that it is heavily used outside of that person’s parent’s basement.

Conditionals allow our programs to become intelligent. They let us program applications that can react to different situations. Is there a logged in user? If not, ask her to log in; otherwise, show her the secret account page. Has the current user paid his bill? If he has, give him access to his account; if not, tell him to pay. These are examples of conditional statements. The program takes a different path through its execution based on the answers to these questions.

CoffeeScript, like almost every other programming language, offers conditionals. These conditional statements will typically be used with the operators and aliases we’ve already seen in this chapter to help the program make more intelligent decisions.

The if Statement

Already in this book, you have seen examples of the if statement at work. The structure is pretty simple.

Example: (source: if.coffee)


if true
  console.log "the statement was true"


Example: (source: if.js)


(function() {

  if (true) console.log("the statement was true");

}).call(this);


Output: (source: if.coffee)


the statement was true


Our example, while incredibly contrived, illustrates the structure of an if statement. We follow the keyword if with whatever our conditional statement is. If that statement returns true we execute the block of code following it. If the conditional statement returns false we skip execution of the code block.

Here is a slightly less-contrived example:

Example: (source: if2.coffee)


today = "Sunday"
if today is "Sunday"
  console.log "Today is Sunday"


Example: (source: if2.js)


(function() {
  var today;

  today = "Sunday";

  if (today === "Sunday") console.log("Today is Sunday");

}).call(this);


Output: (source: if2.coffee)


Today is Sunday


The if/else Statement

There are times when we want to execute some code if the conditional statement is true, and there are times when we want to execute some other code if the statement is false. In these cases we can use the if statement we know and the else keyword to define a block of code to run, should the conditional statement be false.

For example:

Example: (source: if_else.coffee)


today = "Monday"
if today is "Sunday"
  console.log "Today is Sunday"
else
  console.log "Today is not Sunday"


Example: (source: if_else.js)


(function() {
  var today;

  today = "Monday";

  if (today === "Sunday") {
    console.log("Today is Sunday");
  } else {
    console.log("Today is not Sunday");
  }

}).call(this);


Output: (source: if_else.coffee)


Today is not Sunday


As you can see, in our example our conditional was false, so the block of code defined after the else keyword was executed.

CoffeeScript does allow you to write this in a single line of code, which would look something like this:

Example: (source: if_else_1_line.coffee)


today = "Monday"
console.log if today is "Sunday" then "Today is Sunday" else "Today is not Sunday"


Example: (source: if_else_1_line.js)


(function() {
  var today;

  today = "Monday";

  console.log(today === "Sunday" ? "Today is Sunday" : "Today is not Sunday");

}).call(this);


Output: (source: if_else_1_line.coffee)


Today is not Sunday



Tip

Personally, I think that the single line if else then statement is a bit wordy and hard to read, so I would very rarely, if ever, use it.


In JavaScript you can use what is called the ternary operator4 to write that same example in one line of code, which is what CoffeeScript compiles it down to. However, CoffeeScript does not support the ternary operator, so any attempt to use it would result in some rather strange compiled JavaScript. Take a look for yourself:

Example: (source: ternary.coffee)


today = "Monday"
console.log today is "Sunday" ? "Today is Sunday" : "Today is not Sunday"


Example: (source: ternary.js)


(function() {
  var today, _ref;

  today = "Monday";

  console.log((_ref = today === "Sunday") != null ? _ref : {
    "Today is Sunday": "Today is not Sunday"
  });

}).call(this);


Output: (source: ternary.coffee)


false


I’m not going to explain what happened there. Make a note to yourself to revisit this example when you have finished this book to see if you can solve the riddle of why CoffeeScript generated that JavaScript.

The if/else if Statement

Let’s pretend for a moment that we are writing a very basic todo application. When we look at the application we want it do one of three things. If today is Saturday, we want it to show us a list of todos for the day. If it’s Sunday, we want it to tell us to relax and enjoy the day. Finally if it’s neither Saturday nor Sunday, we want it tell us to get to work. How would we write that using the knowledge we have so far? It would look something like this:

Example: (source: if_else_if_1.coffee)


today = "Monday"
if today is "Saturday"
  console.log "Here are your todos for the day..."
if today is "Sunday"
  console.log "Go watch football and relax!"
if today isnt "Saturday" and today isnt "Sunday"
  console.log "Get to work you lazy bum!"


Example: (source: if_else_if_1.js)


(function() {
  var today;

  today = "Monday";

  if (today === "Saturday") console.log("Here are your todos for the day...");

  if (today === "Sunday") console.log("Go watch football and relax!");

  if (today !== "Saturday" && today !== "Sunday") {
    console.log("Get to work you lazy bum!");
  }

}).call(this);


Output: (source: if_else_if_1.coffee)


Get to work you lazy bum!


Although that code does work, it isn’t the most efficient code. For a start we are checking each if statement, even if the first one was true, and we still check the other if statements in case they are also true, which we know will never be the case. Also, our last if statement is a bit repetitive because we are asking similar questions already. Finally, it is also error prone. If want to change from using full day names, like Sunday, to shortened ones, like Sun, we have to make sure we update every reference to Sunday we find.

Using the else if statement, we can easily clean up this example. Here’s how:

Example: (source: if_else_if_2.coffee)


today = "Monday"
if today is "Saturday"
  console.log "Here are your todos for the day..."
else if today is "Sunday"
  console.log "Go watch football and relax!"
else
  console.log "Get to work you lazy bum!"


Example: (source: if_else_if_2.js)


(function() {
  var today;

  today = "Monday";
  if (today === "Saturday") {
    console.log("Here are your todos for the day...");
  } else if (today === "Sunday") {
    console.log("Go watch football and relax!");
  } else {
    console.log("Get to work you lazy bum!");
  }

}).call(this);


Output: (source: if_else_if_2.coffee)


Get to work you lazy bum!


Now doesn’t that look a lot better? It is also a lot more efficient when executed. If today were Saturday, it would execute the first code block and then skip the rest of the else if and else statements, because they are unnecessary.

Later in this chapter we will rewrite this example using the switch statement, which will clean it up even further.

The unless Statement

The Ruby programming language has the concept of the unless statement, and the folks behind CoffeeScript thought it was such a great idea they stole it.

What does the unless statement do? In short, it enables you to put the else before the if. Now, I know you’re scratching your head. It is confusing at first, but it really is straightforward.

When using the unless we are checking to see if our conditional statement is false. If the statement is false, we execute the code block defined below it. Here’s an example:

Example: (source: unless.coffee)


today = "Monday"
unless today is "Sunday"
  console.log "No football today!"


Example: (source: unless.js)


(function() {
  var today;

  today = "Monday";

  if (today !== "Sunday") console.log("No football today!");

}).call(this);


Output: (source: unless.coffee)


No football today!


The same example could be written in any of the following ways:

Example: (source: unless_as_if.coffee)


today = "Monday"
unless today is "Sunday"
  console.log "No football today!"

if not (today is "Sunday")
  console.log "No football today!"

if today isnt "Sunday"
  console.log "No football today!"


Example: (source: unless_as_if.js)


(function() {
  var today;

  today = "Monday";

  if (today !== "Sunday") console.log("No football today!");

  if (!(today === "Sunday")) console.log("No football today!");

  if (today !== "Sunday") console.log("No football today!");

}).call(this);


Output: (source: unless_as_if.coffee)


No football today!
No football today!
No football today!


Of the three examples, I prefer the last example using the isnt alias. I find it to be a bit cleaner and easier to read. The choice, however, is up to you. They are all valid ways of writing the same code.

Inline Conditionals

In addition to the unless keyword, the CoffeeScript team copped the idea of inline conditionals from Ruby. An inline conditional statement allows you to place both the conditional statement and the code block to execute on the same line.

This is easily demonstrated with an example:

Example: (source: inline.coffee)


today = "Sunday"
console.log "Today is Sunday" if today is "Sunday"


Example: (source: inline.js)


(function() {
  var today;

  today = "Sunday";

  if (today === "Sunday") console.log("Today is Sunday");

}).call(this);


Output: (source: inline.coffee)


Today is Sunday


When used with the existential operator, which we covered earlier in this chapter, the inline conditional can help to keep code clean.

Switch/Case Statements

Earlier when we talked about else if statements, I mentioned how we could clean up that code using a switch statement.5 A switch statement lets us build a table of conditionals, which we can then match an object against. Should one of the conditionals match, appropriate code will be executed. We can also give our table an else clause to match, should none of the other conditionals match.

Let’s take a look at our earlier else if example and rewrite it to use the switch statement in CoffeeScript.

Example: (source: switch1.coffee)


today = "Monday"
switch today
  when "Saturday"
    console.log "Here are your todos for the day..."
  when "Sunday"
    console.log "Go watch football and relax!"
  else
    console.log "Get to work you lazy bum!"


Example: (source: switch1.js)


(function() {
  var today;

  today = "Monday";

  switch (today) {
    case "Saturday":
      console.log("Here are your todos for the day...");
      break;
    case "Sunday":
      console.log("Go watch football and relax!");
      break;
    default:
      console.log("Get to work you lazy bum!");
  }

}).call(this);


Output: (source: switch1.coffee)


Get to work you lazy bum!


As you can see, our today variable is checked against the defined case statements. Because neither of the case statements matched the today variable we passed in, the program fell through to the else statement we defined at the end of the switch statement. It’s worth pointing out that we don’t need to define an else block at the end. If we didn’t define the else in our example, nothing would have been printed out.

The more observant of you will have noticed the break keyword in the compiled JavaScript output at the end of each of the case statements. In JavaScript it is possible to let the switch statement keep falling through and keep matching more case statements. This is almost never wanted, and is often the source of many bugs. The most common bug is that it matches a case, executes the appropriate code, and ends up also executing the default code block at the bottom. The break keyword will tell the switch to stop executing and to stop trying to match other cases. This is another example of CoffeeScript trying to cover your back and help you write code with fewer bugs.

The switch statement also enables us to pass a comma-separated list of values to match against the case keyword. This makes it possible for us to execute the same code block for multiple matches. Suppose we wanted a program that would check to see if today was a weekend day. If it was indeed a weekend day, it would tell us to relax; otherwise, it would tell us to work. We could do that like this:

Example: (source: switch2.coffee)


today = "Sunday"
switch today
  when "Saturday", "Sunday"
    console.log "Enjoy your #{today}!"
  else
    console.log "Off to work you go. :("


Example: (source: switch2.js)


(function() {
  var today;

  today = "Sunday";

  switch (today) {
    case "Saturday":
    case "Sunday":
      console.log("Enjoy your " + today + "!");
      break;
    default:
      console.log("Off to work you go. :(");
  }

}).call(this);


Output: (source: switch2.coffee)


Enjoy your Sunday!


With that, our exploration of the wonderful switch statement comes to a close. There is a lot of debate among developers as to when, where, or if you should ever use switch statements. They are not something I use on a day-to-day basis, but they definitely have their place. I’ll let you decide when they are of use to you and your application.

Wrapping Up

In this chapter we’ve covered a lot of ground. We’ve discussed the various operators in CoffeeScript and how, if at all, they map to JavaScript. We’ve seen a few of the places where CoffeeScript tries to help us write better JavaScript code. Aliases showed us how to write “prettier” code that reads more like English than “computer.” You’ve seen how to build conditional statements to help make your programs more intelligent and to help execute the correct bit of code depending on certain conditions. Finally, we explored how the switch statement can help you clean up complex code.

In the original outline for this book, this chapter was originally part of Chapter 2, “The Basics,” but I felt there was so much information here that it deserved its own chapter. This chapter could have been called “The Basics—Part 2.” I’m telling you this because, armed with the knowledge contained within this chapter and Chapter 2, we have covered the basic building blocks of CoffeeScript. We can now start looking at the really fun stuff.

Notes

1. http://en.wikipedia.org/wiki/Operator_(programming)

2. http://en.wikipedia.org/wiki/Conditional_(programming)

3. http://www.yaml.org/spec/1.2/spec.html

4. http://en.wikipedia.org/wiki/Ternary_operation

5. http://en.wikipedia.org/wiki/Switch_statement

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.124.21