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 +5is compiled tofoo(+5) - function with arguments:
(a, b) -> a + b isis 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 tothisorthis., 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
applyorcallmethod (function is also object):cat.setName.apply hourse, ['porny'] - The
newkeyword 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
newkeyword before a function call, then the newly created object is the context - When calling a function with
callorapply, 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 ?returnstruewhen the variable exists in current scope (and by inheritage its father scope), and it’s notnullorundefinedunlessis an alias toif nota?bis an alias toif a? then a else bc ?= dis an alias toc = d unless c?- default value of function argument:
(name = 'jack') -> ... - CoffeeScript’s default value is based on
?test, thus explicitly passingnullorundefinedto an argument will also make it using the default value. - In CoffeeScript (as in Javascript), logical operatans can be anything besides
trueandfalse.null,undefined,0and""are consideredfalseand any other values are consideredtrue - In CoffeeScript (as in Javascript), logical operations return their operatans instead of
trueandfalselike in other languages:c = a or bis equivalent toc = if a then a else b,c = a and bequalsc = 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,otherArgswill 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.attrto 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?cis an alias toif a? and a.b? then a.b else cfoo?()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,valueis optional - Iterate instance attributes, rather than static attributes, use
for own ... - Iterate array:
for val in array by step,stepis optional, defaulting to 1 - When iterating a range
[max..min],stepcould be negative. When iterating an array,stepshould not be negative, otherwise the iteration will not stop - Optional conditioning:
for ... when ..., works for bothofandin ofandinused 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
windowin browser environment orglobalin 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.datato 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) superwithout 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