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 asconsole.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 towhen
+then
default
in javascript translates toelse
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 inheritancesuper
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);
};