Click here to Skip to main content
Click here to Skip to main content
Technical Blog

Tagged as

A brief introduction to CoffeeScript

, 13 Aug 2011 CC (ASA 3U)
Rate this:
Please Sign up or sign in to vote.
A brief introduction to CoffeeScript

Editorial Note

This article appears in the Third Party Product Reviews section. Articles in this section are for the members only and must not be used by tool vendors to promote or advertise products in any way, shape or form. Please report any spam or advertising.

CoffeeScript is a little language that compiles into JavaScript. The code compiles one-to-one into the equivalent JS, and there is no interpretation at runtime. You can use any existing JavaScript library seamlessly (and vice-versa).

The syntax of CoffeeScript is inspired by Ruby and Python, and implements many features from those two languages. This introduction references The Little Book on CoffeeScript and the official site of CoffeeScript heavily.

You are required to be familiar with JavaScript’s internals and idioms, and Ruby’s and/or Python’s syntax.

Overview

Some CoffeeScript codes are listed below for a quick overview. If you are familiar with JavaScript and Ruby, it will be very intuitive.

# Assignment:
number   = 42
opposite = true

# Conditions:
number = -42 if opposite

# Functions:
square = (x) -> x * x

# Arrays:
list = [1, 2, 3, 4, 5]

# Objects:
math = 
  root:   Math.sqrt
  square: square
  cube:   (x) -> x * square x

# Splats:
race = (winner, runners...) ->
  print winner, runners

# Existence:
alert "I knew it!" if elvis?

# Array comprehensions:
cubes = (math.cube num for num in list)

Syntax

Comments come first:

# A single-line comment

###
  A multiline comment, perhaps a LICENSE.
###

CoffeeScript simply removes global variables. Behind the scenes, CoffeeScript wraps up scripts with anonymous function, keeping the local context, and automatically prefixes all variables assignments with var. For example, take this simple variable assignment in CoffeeScript:

myVariable = "test"

The compiled JavaScript will be:

var myVariable;
myVariable = "test";

However, sometimes it’s useful to create global variables. You can do with the following pattern:

exports = this
exports.MyVariable = "foo-bar"

In the root context, this is equal to the global object, and by creating a local exports variable you’re making it really obvious to anyone reading your code exactly which global variables a script is creating.

CoffeeScript removes the rather verbose function statement, and replaces it with a thin arrow: –>. Functions can be one liners, or indented on multiple lines. The last expression is implicitly returned. The following two code snippets are equivalent to the third JavaScript code snippet:

func = -> "bar"

func = ->
  # An extra line
  "bar"

var func;
func = function() {
  return "bar";
};

You can also specify arguments in a pair of parenthesis before the arrow.

times = (a, b) -> a * b

CoffeeScript supports default arguments too, for example:

times = (a = 1, b = 2) -> a * b

It will be compiled to:

var times;
times = function(a, b) {
  if (a == null) {
    a = 1;
  }
  if (b == null) {
    b = 2;
  }
  return a * b;
};

You can also use splats to accept multiple arguments, denoted by

sum = (nums...) ->
  result = 0
  nums.forEach (n) -> result += n
  result

Functions can be invoked exactly as in JavaScript. However, like Ruby, CoffeeScript will automatically call functions if they are invoked with at least one argument.

a = "Howdy!"

alert a
# Equivalent to:
alert(a)

alert inspect a
# Equivalent to:
alert(inspect(a))
# and recommended to be:
alert inspect(a)

Object literals can be specified exactly as in JavaScript. However, CoffeeScript makes it easier.

object1 = {one: 1, two: 2}

# Without braces
object2 = one: 1, two: 2

# Using new lines instead of commas
object3 =
  one: 1
  two: 2

User.create(name: "John Smith")

Likewise, arrays can use whitespace instead of comma separators, although the square brackets ([]) are still required.

array1 = [1, 2, 3]

array2 = [
  1
  2
  3
]

array3 = [1,2,3,]

CoffeeScript has also stripped the trailing commas in array3, another common source of cross-browser errors.

Flow control looks like Ruby, which doesn’t require too much explanation.

if true == true
  "We're ok"

if true != true then "Panic"

if 1 > 0 then "Ok" else "Y2K!"

alert "It's cold!" if heat < 5

if not true then "Panic"

unless true
  "Panic"

if true is 1
  "type coercion fail"

if 10 == "+10" then "type coercion fail"

Note that CoffeeScript is converting == operators into === and != into !==, since it’s recommended to always use the strict equality operator, and explicitly convert types if need be.

CoffeeScript brings Ruby style string interpolation to JavaScript. Multiline strings are also allowed, without having to prefix each line with a +.

favorite_color = "Blue. No, yel..."
question = "Bridgekeeper: What.. is your favorite color?
            Galahad: #{favorite_color}
            Bridgekeeper: Wrong!
            "

Array iteration in JavaScript has a rather archaic syntax. CoffeeScript comes to the rescue, with a beautiful syntax:

for name in ["Roger", "Roderick", "Brian"]
  alert "Release #{name}"

for name, i in ["Roger the pickpocket", "Roderick the robber"]
  alert "#{i} - Release #{name}"

# The postfix form:
release prisoner for prisoner in ["Roger", "Roderick", "Brian"]

# Filter with Python comprehensions:
prisoners = ["Roger", "Roderick", "Brian"]
release prisoner for prisoner in prisoners when prisoner[0] is "R"

# Iterate over properties in objects.
# Instead of the in keyword, use of.
names = sam: seaborn, donna: moss
alert("#{first} #{last}") for first, last of names

Using if for null checks in JavaScript is common, but has a few pitfalls. CoffeeScript existential operator ? returns true unless a variable is null or undefined, similar to Ruby’s nil?.

praise if brian?

You can also use it in place of the || operator:

velocity = southern ? 40

If you’re using a null check before accessing a property:

blackKnight.getLegs()?.kick()
whiteKnight.guard? us

The lines above will be compiled into:

var _ref;
if ((_ref = blackKnight.getLegs()) != null) {
  _ref.kick();
}
if (typeof whiteKnight.guard === "function") {
  whiteKnight.guard(us);
}

Idioms

Every language has a set of idioms and practices, which will delight veterans.

# Each
myFunction(item) for item in array

# Map
result = (item.name for item in array)

# Select
result = (item for item in array when item.name is "test")

# Select more
scores = [49, 58, 76, 82, 88, 90]
passed = (score for score in scores when score > 60)

# English style equality test
string = "migrating coconuts"
string == string    # true
string is string    # true
string != string    # false
string isnt string  # false

hash or= {}         # hash || (hash = {});
has ?= {}           # if (typeof hash !== undefined && hash !== null) {
                    #   hash;
                    # } else {
                    #   hash = {};
                    # };

# Destructing assignments
someObject = { a: 'value for a', b: 'value for b' }
{ a, b } = someObject
console.log "a is '#{a}', b is '#{b}'"

Conclusion

CoffeeScript’s beautiful syntax is amazing. Similar ideas have been extended to other languages, such as Sass for CSS, Haml for markups, and Zen Coding, which provides a new way of writing HTML and CSS code. This kind of extension may be useful in a very very long time, just like running languages on JVM.

This article is only an introduction. For more details, especially classes of CoffeeScript, see The Little Book on CoffeeScript.

EDIT: altJS is a collection of languages and tools aimed at rebooting JavaScript and making it better. It may be very useful.

License

This article, along with any associated source code and files, is licensed under The Creative Commons Attribution-Share Alike 3.0 Unported License

Share

About the Author

stfairy
Student Shanghai Jiao Tong University
China China
No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150327.1 | Last Updated 13 Aug 2011
Article Copyright 2011 by stfairy
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid