Coffeescript

Basic rules

  • Uses whitespace to delimit blocks of code
  • {} Instead, use indentation.
  • () implicit call wraps forward to the end.
    • console.log sys.inspect object is same as console.log(sys.inspect(object));

1. Function

Function with an argument

square = (x) -> x*x

Function without an argument

helloWorld = -> console.log "Hello World"

Implicit return

# returns the last command
do = (action) ->
    "Let's do #{action}"

Default argument

# default argument is 'nothing'
do = (action = 'nothing') -> 
    "Let's do #{action}"

2. Arrays

Same syntax as javascript

arr = ["this", "is", "an", "array"]

Array items can be separated by lines instead of commas

arr = [
    "this"
    "is"
    "an"
    "array"
]

Slicing Array

numbers = [1,2,3,4,5,6,7,8,9]

# Two dots mean it includes the last index
# In this case, start is [1,2,3]
start = numbers[0..2]

# Three dots mean it excludes the last index
# In this case, middle is [4,5]
middle = numbers[3...6]

# Omitted first index implies 0
# In this case, end is [7,8,9]
end = numbers[6..]

# Omitted last index implies the length of the array
# In this case, copy is [1,2,3,4,5,6,7,8,9]
copy = numbers[..]

Array membership

in is used to test membership in an array

1 in [1,2,3,4]
# returns true

3. String

Multiline strings are allowed.

mobyDick = "Call me Ishmael. Some years ago --
    never mind how long precisely -- having little
    or no money in my purse, and nothing particular
    to interest me on shore, I thought I would sail
    about a little and see the watery part of the
    world..."

Block strings for preserving indentation

html = """
        <strong>
                cup of coffeescript
        </strong>
        """

Block comments

###
This is a comment
###

2. Objects

Same syntax as javascript

obj = {name: "this is an object", language: "english"}

Object items can be written like YAML, without the braces

obj = 
    name: "this is an object"
    language: "english"

Object Membership

"john" in {john: 1, mary: 2, susan:3}
# returns true

3. Lexical Scoping

Everything is naturally declared within lexial scope

outer = 1
change = ->
    inner = -1
    outer = 10
inner = change()

Immediately Invoked Function

do is used to immeidately invoke a function in order to make sure variables are closed over. For example:

do (x) -> x*x

is same as:

(function(x){
    return x * x;
}());

Also, there is no global variable. If I really want to use window level global variable, I need to explicitly say it.

window.globalVariable = 1

4. Conditionals

if sexy and iKnowIt
    wiggle()
    wiggle()
else
    workOut()

postfix IF

singing = true
mood = "good" if singing

IF + THEN

date = if friday then sue else jill
# same as
# friday ? sue : jill;

Switch

  • case: in javascript translates to when + then
  • default in javascript translates to else in the end switch day when “Mon” then go work when “Tue” then go relax when “Thu” then go iceFishing when “Fri”, “Sat” if day is bingoDay go bingo go dancing when “Sun” then go church else go work

5. Loops

Comprehensions instead of Loops

Comprehensions are like for loops but is an expression, which can be passed around

# Iterating through an array and returning squares
square = (x) -> x*x
square(x) for x in [1,2,3,4,5]

# Adding two values
counter = (x,y) -> x + " is number " + y
counter(x, index) for x, index in ["John", "Mary", "Susan", "Ethan"]

# Using conditionals with comprehensions #1
square = (x) -> x*x
square(x) for x in [1,2,3,4,5] when x > 2

# Using conditionals with comprehensions #2
counter = (x,y) -> x + " is number " + y
counter(x, index) for x, index in ["John", "Mary", "Susan", "Ethan"] when x isnt "John"

Comprehension for objects

Use of intead of in

children = John:1, Mary:2, Susan:3, Ethan:4
"#{child} is #{age}" for child, age of children

While loop

While loop in Coffeescript can be used as an expression. Which means it as a return value. For example:

num = 6
lyrics = while num -= 1
  "#{num} little monkeys"

In this cas,e lyrics is “1 monkeys”

The above code is same as:

num = 6
lyrics = "#{num} little monkeys" while num -= 1

6. Misc

Logic

or is same as ||

and is same as &&

not is same as !

on is same as true

yes is same as true

off is same as false

no is same as false

is is same as ===

isnt is same as !==

Instance variable

@property is same as this.property

Existential ?

Just add ? to a variable to check if it’s not null and not undefined

mindless = true if not mind?

7. Class

Class declaration

class Animal
    constructor: (name) -> 
        @name = name        # assigning to instance variable
    move: (meters) ->
        alert @name + "{meters}m."
    price: 5        # instance variable

Class inheritance

  • extends is used for inheritance
  • super is used for calling its super class method class Snake extends Animal move: –> alert “slithering…” super 5

Instantiating a class

sam = new Snake "Sammy the Python"

Accessing prototype

String::dasherize = ->
      this.replace /_/g, "-"

in javascript, it would look like this:

String.prototype.dasherize = function() {
    return this.replace(/_/g, "-");
};

8. Destructuring assignment

Basically it’s a feature where an assignment can extract out values from right to left.

A. Array assignment

weatherReport = (location) -> [location, 72, "Mostly Sunny"]
[city, temp, forecast] = weatherReport "Berkeley, CA"

B. Object assignment

Here’s a basic usage:

drink = name: 'coffee', caffeine: true
{name: name, caffeine, caffeine} = drink
# At this point, 'name' is "coffee", and "caffeine" is true

We can even go shorter. no need to do the redundant {name: name, caffeine: caffeine}

drink = name: 'coffee', caffeine: true
{name, caffeine} = drink
# At this point, 'name' is "coffee", and "caffeine" is true

It doesn’t matter how deep we go, it still manages to extract the relevant fields

kid = name: 'John', age: 12, address: { city: 'San Francisco', state: 'CA' }
{ address: { city, state } } = kid
# This resluts in 'city' being assigned as 'San Francisco', and 'state' being assigned as 'CA'

Destructuring is also useful for class initialization

class Person
    constructor: (options) -> {@name, @age, @height} = options

9. Context binding

=> (fat arrow) is used instead of -> (normal arrow)

A. When thin arrow “–>” is wrong

For example, this is wrong, because “this” inside the click callback is the button object.

class Counter
    constructor: ->
        @count = 0
        $("button").click(e) ->
            @count++

In javascript it’s same as doing:

var Counter = function(){
    this.count = 0;
    $("button").click(function(e){
        this.count++;
    });
};

B. Fat arrow “=>” to the rescue

Instead, the click callback should use fat arrow, like this

class Counter
    constructor: ->
        @count = 0
        $("button").click(e) =>
            @count++

In javascript it’s same as doing:

var Counter = function(){
    this.count = 0;
    _.bind($("button").click(function(e){
        this.count++;
    }), this);
};