CoffeeScript Study Notes
November 17, 2014
This is my study note after reading CoffeeScript: Accelerated JavaScript Development. Only the most important points that I’m not familiar with are recorded, with some minor changes in the order.
Functions, scope, and context
- function definination:
-> 'hello'
- terminal output:
console.log 'hello'
- run a function:
do -> 'hello'
, or(-> 'hello')()
- auto return last statement’s value, or use
return
- functions without return value perform better
- named function is a variable assigned a function value:
hi = -> 'hello'
- thus functions must be defined before they are used
- string interpolation:
"hello, #{expression}!"
- single quoted string: no string interpolation
- operator
+
doesn’t ignore spaces:foo +5
is compiled tofoo(+5)
- function with arguments:
(a, b) -> a + b
is
is compiled to===
- test type:
if typeof num is 'number'
- test integer:
if num is Math.round num
- throw exception:
throw 'something wrong'
- capture exception:
try ... \n catch e \n console.log e
- the only way to create a scope is by defining a function
- If a variable is defined before a function defination, inside the function a variable with the same name is always considered refering to the one in the outer scope. Otherwise if a function creates or uses a variable that is not defined before the function itself, it’s a local variable only available inside the function scope.
- Such relative position between variable and function definations is the only way to determine whether a variable is local to the function scope. Note that assigning to a variable inside a function does not create a local variable, it’s merely re-assigning to it.
- An alternative comprehension is that function scope is a sub-scope of its outer scope, which inherites all the variables. But new variables inside the function scope could not live outside.
- Inside a named function, the function itself is always available since it’s created before it’s defined
- The only way to define a variable is by assigning to it.
@
is an alias tothis
orthis.
, meaning the context (caller) of a function. When a method of an object is called, its context is the object.- It’s possible to call a function with a different context by using the function’s
apply
orcall
method (function is also object):cat.setName.apply hourse, ['porny']
- The
new
keyword takes a function, not just objects, meaning “don’t return the function’s value, instead create an object and call the function, using this object as the function’s context, and then return the object”. - A little summary (earlier has higher privilege):
- If there is the
new
keyword before a function call, then the newly created object is the context - When calling a function with
call
orapply
, then the first argument is the context - When calling an object’s method, the object is the context
- Otherwise the function’s context is the global context.
- If there is the
- There is also a way to always use a particular object as the context, regardless where and how the function is called: the fact arrow
=>
. A function using the fact arrow will always have the same context as where it is defined. - There’s a convenient alias to change object’s attribute:
setName = (@name) ->
is equivalent tosetName = (name) -> @name = name
?
returnstrue
when the variable exists in current scope (and by inheritage its father scope), and it’s notnull
orundefined
unless
is an alias toif not
a?b
is an alias toif a? then a else b
c ?= d
is an alias toc = d unless c?
- default value of function argument:
(name = 'jack') -> ...
- CoffeeScript’s default value is based on
?
test, thus explicitly passingnull
orundefined
to an argument will also make it using the default value. - In CoffeeScript (as in Javascript), logical operatans can be anything besides
true
andfalse
.null
,undefined
,0
and""
are consideredfalse
and any other values are consideredtrue
- In CoffeeScript (as in Javascript), logical operations return their operatans instead of
true
andfalse
like in other languages:c = a or b
is equivalent toc = if a then a else b
,c = a and b
equalsc = if a and b then b else if not a and not b then a else if not a and b then a else if a and not b then b
- In function definations, when using an expression as default value, the expression will be evaluated inside the function before anything else. Thus
foo = (arg = @name) -> ...
is the same asfoo = (arg) -> \n arg = @name \n ...
- Variant length arguments:
foo = (arg1, otherArgs...) -> ...
. Inside the function,otherArgs
will be an array. - Variant length argument need not to be the last argument: it can be the first or anywhere. Non-variant arguments have privilege.
- When calling a function,
...
could be attached to an array to spread it as function’s arguments:foo(1, arr...)
is the same asfoo(1, arr[0], arr[1], ...)
.
Collections and iteration
- Create an object:
obj = new Object()
, orobj = {}
- If the name of an attribute doesn’t contain any special character, then use
obj.attr
to refer to it. Otherwise useobj['attr']
. x = 'name' \n obj[x]
is equal toobj.name
. Any expression beteen the brackets will be evaluated and converted to string.- JSON object: ` foo = {name: ‘john’, age: 50}`. If attribute name contains special characters, it must be surrounded by quotation marks.
- In CoffeeScript, the curly brackets are optional, and if written on seperate lines, the commas could be omitted too.
- In CoffeeScript,
x = 1 \n obj = {x}
is the same asx = 1 \n obj = {x: x}
but only when curly brackets are used too. a?.b?c
is an alias toif a? and a.b? then a.b else c
foo?()
is an alias toif foo? then foo()
- Array:
names = ['james', 'jack', 'john']
, same asnames = new Array() \n names[0] = 'james' \n names[1] = 'jack' \n names[2] = 'john'
- Array are still objects (hash tables), whose indexes are strings, rather than integers like in other languages
- Quick range:
a = [1..3]
. If begin index greater than end index, then return reversed array - Array slicing:
arr[1..3]
orarr[1..]
, orarr[1..-1]
. If begin index greater than end index, then return an empty array - Assigning to array slice:
arr[1..3] = arr2
. If range is empty, then insert before the begin index - Iterate attributes of object:
for key, value of object
,value
is optional - Iterate instance attributes, rather than static attributes, use
for own ...
- Iterate array:
for val in array by step
,step
is optional, defaulting to 1 - When iterating a range
[max..min]
,step
could be negative. When iterating an array,step
should not be negative, otherwise the iteration will not stop - Optional conditioning:
for ... when ...
, works for bothof
andin
of
andin
used as operators to test existence:names = ['james', 'jack', 'john'] \n 'jack' in names
, orgermanToEnglish = {'ja': 'yes', 'nein': 'no'} \n 'ja' of germanToEnglish
- Conditional iteration:
dosomething() while test()
ordosomething() until test()
- Infinite looping:
loop \n ... break ...
- List comprehension:
arr = (-num for num in [1..5] by 2)
– single line form need to put iteration body in front and use paratheses.arr = for num in [1..5] by 2 \n num + 2
- Array model match:
[first, middle, last] = ['Joey', 'T', 'Plumber']
which is equal tofirst = 'Joey'; middle = 'T'; last = 'Plumber'
- Variant lengh argument can also be used in array model match:
[best, rest...] = students
- Object model match:
{X: myX, y: myY} = Rect
==myX = Rect.X; myY = Rect.Y
- Very convenient:
{X, Y} = Rect
==X = Rect.X; Y = Rect.Y
- Array and object model match mixed:
{languages: [favorite, others...]} = resume
==[favorite, others...] = resume.languages
Modules and classes
- CoffeeScript wraps every file to a single namespace, so a file is a module.
- To share data across modules, attach data to the global object
window
in browser environment orglobal
in Node.js - Better practice is to attach data to an attribute with the same name as the current file. Then in other modules simply use
modulename.data
to refer to it - class defination:
class Tribble \n property: 0 \n method: -> ...
- Constructor is defined by
constructor: -> ...
- Class (static) property and method are written with a
@
prefix, with the exception of the constructor - Instance property and method are written as is
- Inside instance methods and the constructor,
@
means the instance, while inside static methods except the constructor,@
means the class - Class inheritage is defined by
class A extends B
- Inside child class methods,
super()
means call the same method of the father (with no arguments) super
without paratheses is a special shortcut for passing all the current method’s arguments to its father- To test whether an object is an instance of a class, use
a instanceof A
- Switch statement:
switch caption \n when 'Kirk', 'Picard', 'Archer' \n ... \n when 'Janeway' new Voyager() \n else throw new Error("wrong!")
Web interactivity with JQuery
- JQuery selectors are a superclass of CSS
- Name a JQuery object by a prefix
$
is a common coding convention - JQeury getter functions only get the first match, with the exception of
text()
which returns the joined string of all matches - Setter functions apply to all matches
$("#header imag")
is the same as$("#header").find("img")
$("#header > img")
is the same as$("#header").children("img")
$("li:has(a)")
to select the list items that contain links- Binding events:
$("h1").click -> $(@).html $(@).html + "!"
- In binded event handler functions,
@
is the current DOM object that triggers the event
Server-side apps with Node.js
- Node.js module export and include: in included file attach data to
exports
, in other modules useutil = require './util'
- In Javascript files, if want to include CoffeeScript module, use
require('coffee-script')
before including the module - If no path is specified for the included module, Node will search its path definedin
require.paths
- CoffeeScript
do (x, sum) -> ...
is same as((x, sum) -> ...)(x, sum)
, used to create closures