$ npm install -g coffee-script
-b | --bare | 컴파일된 JavaScript를 함수로 감싸지 않는다. |
-c | --complie | JavaScript로 컴파일하고, .js 파일로 저장한다. |
-e | --eval | 명령어 라인에서 전달받은 문자열을 컴파일한다. |
-h | --help | 도움말을 출력한다. |
-i | --interactive | 대화식의 CoffeeScript REPL 모드로 수행한다. |
-j | --join | 컴파일 전에 스크립트들을 합친다. |
-m | --map | generate source map and save as .js.map files |
-n | --nodes | 파서가 생성한 트리를 보여준다. |
--nodejs | node.js로 전달할 옵션을 지정한다. | |
--no-header | suppress the "Generated by" header | |
-o | --output | 컴파일되는 JavaScript 파일 저장 경로를 저정한다. |
-p | 컴파일된 JavaScript를 표준 출력으로 보낸다. | |
-r | --require | 스크립트 수행 전에 필요한 라이브러리를 지정한다. |
-s | --stdio | 표준 입출력을 통해 스크립트들을 컴파일한다. |
-l | --literate | treat stdio as literate style coffee-script |
-t | --tokens | Lexer가 만든 토큰을 보여준다. |
-v | --version | CoffeeScript 버전 정보를 나타낸다. |
-w | --watch | 스크립트를 지켜보고 있다 변경되면 다시 명령을 수행한다. |
$ coffee -c mochaccino.coffee
# 자바스크립트로 컴파일 되어 mochaccino.js를 현재 위치에 저장한다.
$ coffee -co output source
# source 디렉토리에 있는(하위 디렉토리 포함) 모든 .coffee 파일을 컴파일한 뒤 그에 해당하는
# .js 파일들을 output 디렉토리에 생성한다.
$ coffee -cwo js coffee
code:
-> 'Hello, functions!'
code:
console.log do -> 'Hello, functions'
result:
Hello, functions
code:
hi = -> 'Hello, functions!'
console.log hi()
result:
Hello, functions!
code:
greeting = (subject) -> "Hi, #{subject}"
console.log greeting 'CoffeeScript'
result:
Hi, CoffeeScript
code:
odd = (num) -> num % 2 is 1
# is는 JavaScript의 === 과 같다.
console.log odd(3)
result:
true
code:
odd = (num) ->
if typeof num is 'number'
if num is Math.round num
if num > 0
num % 2 is 1
else
throw "#{num}는 양수가 아니다."
else
throw "#{num}는 정수가 아니다."
else
throw "#{num}는 숫자가 아니다."
try
odd 5.1
catch e
console.log e
result:
5.1는 정수가 아니다.
code:
odd = (num) ->
unless typeof num is 'number'
throw "#{num} is not a number"
unless num is Math.round num
throw "#{num} is an integer"
unless num > 0
throw "#{num} is not positive"
num % 2 is 1
try
odd 5.1
catch e
console.log e
result:
5.1 is an integer
code:
age = 99
reincarnate = -> age = 0
reincarnate()
console.log "I am #{age} years old"
result:
I am 0 years old
code:
reincarnate = -> age = 0
age = 99
reincarnate()
console.log "I am #{age} years old"
# 모든 함수는 범위를 만들고, 범위를 생성하는 유일한 방법은 함수 정의를 통해서다.
# 아니면 전역 범위.
result:
I am 99 years old
code:
setName = (name) -> @name = name
cat = {}
cat.setName = setName
cat.setName 'Mittens'
console.log cat.name
pig = {}
setName.apply pig, ['Babe']
# setName.call pig, 'Babe' 와 같다.
console.log pig.name
horse = {}
cat.setName.apply horse, ['Mr. Ed']
console.log horse.name
Dog = setName
dog1 = new Dog('Jimmy')
dog2 = new Dog('Jake')
console.log dog1.name
console.log dog2.name
setName 'LuLu'
console.log name
console.log @name
result:
Mittens
Babe
Mr. Ed
Jimmy
Jake
LuLu
undefined
code:
apply = (callback) -> callback()
Dog = ->
callback = => @name = 'Merry'
# var callback = (function() { this.name = 'Merry'; }).bind(this);
apply callback
dog = new Dog()
console.log dog.name
result:
Merry
code:
setName = (@name) ->
# setName = (name) -> @name = name
setName 'naki'
console.log name
result:
naki
code:
ringFireAlarm = (isDrill = true) -> isDrill
console.log ringFireAlarm()
console.log ringFireAlarm(false)
result:
true
false
code:
chooseMeals = (breakfast = 'waffles', lunch = 'gyros', dinner = 'pizza') ->
console.log breakfast, lunch, dinner
chooseMeals null, 'burrito', null
result:
waffles burrito pizza
code:
dontTryThisAtHome = (noArgNoProblem = @iHopeThisWorks()) ->
...
- undefined 또는 null 인지 채크한다.
- x? 라고 하면 'x가 존재하는가?' 라고 생각하면 된다.
code:
a = 'a defined'
b = 'b defined'
console.log a ? b
console.log c ? b
myFun?()
myFun = (c) ->
c ?= a # c가 정의되지 안았다면 값 a로 정의.
console.log "myFun: c = #{c}"
myFun()
myFun?() # myFun가 존재한다면 실행.
reuslt:
a defined
b defined
myFun: c = a defined
myFun: c = a defined
code:
refine = (wheat, chaff...) ->
console.log "The best: #{wheat}"
console.log "The rest: #{chaff.join(', ')}"
refine 'great', 'not bad', 'so-so', 'meb'
sandwich = (beginning, middle..., end) ->
console.log beginning, middle, end
sandwich 'apple', 'tomato'
# Splats가 아닌 인자부터 우선 지정된다.
spoiler = (fillter..., theEnding) ->
console.log theEnding
spoiler 'Darth vader is Luke\'s father!'
result:
The best: great
The rest: not bad, so-so, meb
apple [] tomato
Darth vader is Luke's father!
code:
birds = ['duck', 'duck', 'duck', 'duck', 'goose!']
[ducks..., goose] = birds
console.log ducks
console.log 1, 2, 3, 4
arr = [1, 2, 3]
console.log arr, 4
console.log arr..., 4
result:
[ 'duck', 'duck', 'duck', 'duck' ]
1 2 3 4
[ 1, 2, 3 ] 4
1 2 3 4
code:
father =
name: 'John'
daughter:
name: 'Jill'
son:
name: 'Jack'
console.log father
result:
{ name: 'John',
daughter: { name: 'Jill' },
son: { name: 'Jack' } }
code:
delta = '\u0394'
greekUnicode = {delta}
console.log greekUnicode
users = {'naki', 'miki'}
console.log users
result:
{ delta: 'Δ' }
{ naki: 'naki', miki: 'miki' }
code:
a = b?.property ? c # good
code:
obj?.greet()
obj = {}
obj?.greet?()
obj.greet = -> console.log 'Hello!!'
obj?.greet?()
result:
Hello!!
code:
console.log [1..5]
console.log [1...5]
console.log [5..1]
console.log [5...1]
result:
[ 1, 2, 3, 4, 5 ]
[ 1, 2, 3, 4 ]
[ 5, 4, 3, 2, 1 ]
[ 5, 4, 3, 2 ]
code:
console.log ['a', 'b', 'c', 'd'].slice 0, 3
console.log ['a', 'b', 'c', 'd'][0...3]
console.log ['a', 'b', 'c', 'd'][0..3]
console.log ['a', 'b', 'c', 'd'][3...0]
# console.log(['a', 'b', 'c', 'd'].slice(3, 0))
console.log 'The year is 3022'[-4..]
console.log ['this', 'that', 'the other'][1..]
console.log ['this', 'that', 'the other'][1...]
result:
[ 'a', 'b', 'c' ]
[ 'a', 'b', 'c' ]
[ 'a', 'b', 'c', 'd' ]
[]
3022
[ 'that', 'the other' ]
[ 'that', 'the other' ]
code:
arr = ['a', 'c']
arr[1...2] = ['b']
console.log arr
arr = ['a', 'c']
arr[1...1] = ['b']
console.log arr
arr = ['a', 'c']
arr = ['b', arr...]
console.log arr
steveAustin = ['regular', 'guy']
replacementParts = ['better', 'stronger', 'faster']
steveAustin[0..] = replacementParts
console.log steveAustin
result:
[ 'a', 'b' ]
[ 'a', 'b', 'c' ]
[ 'b', 'a', 'c' ]
[ 'better', 'stronger', 'faster' ]
code:
obj = naki: 'hi, naki', miki: 'hi, miki'
for key, value of obj # JavaScript의 for in 과 같다.
console.log key, value
# 대상이 객체일때 사용한다.
console.log '-----------------------'
Obj2 = ->
Obj2.prototype = obj
obj2 = new Obj2()
obj2.john = 'hi, john'
console.log obj2.hasOwnProperty('naki')
console.log obj2.hasOwnProperty('john')
for key, value of obj2
console.log key, value
for own key, value of obj2
console.log key, value
console.log '-----------------------'
array = ['naki', 'miki', 'suni', 'mooni', 'youghee']
for value in array
console.log value
# 대상이 배열일때 사용한다.
console.log '-----------------------'
sum = 0
for value in [1..10]
sum += value
console.log 'sum: ', sum
result:
naki hi, naki
miki hi, miki
-----------------------
false
true
john hi, john
naki hi, naki
miki hi, miki
john hi, john
-----------------------
naki
miki
suni
mooni
youghee
-----------------------
sum: 55
code:
decimate = (army) ->
execute(soldier) for soldier in army by 10
# 10단위씩 실행한다.
animate = (startTime, endTime, framesPerSecond) ->
for pos in [startTime..endTime] by 1 / framesPerSecond
addFrame pos
# 분수도 가능하다.
countdown = (max) ->
console.log x for x in [max..0] by -1
# 음수값도 사용할 수 있지만 배열에서는 사용할 수 없다.
code:
fruits = ['apple', 'cherry', 'tomato']
console.log 'tomato' in fruits
germanToEnglish = {ja: 'yes', nein: 'no'}
console.log 'ja' of germanToEnglish
console.log germanToEnglish['ja']?
result:
true
true
true
code:
makeHay() while sunShines()
makeHay() until sunSets() # while not
loop
console.log 'Home'
break if @flag is true
console.log 'Sweet'
@flag = true
a = 0
loop break if ++a > 999 console.log a # 1000
# loop는 접두 표기를 사용한다.
code:
negativeNumbers = (-num for num in [1, 2, 3, 4])
console.log negativeNumbers
chars = ['a', 'b', 'c']
handlKeyPress = -> chars.pop()
keysPressed = (char while char = handlKeyPress())
console.log keysPressed
code = ['U', 'U', 'D', 'D', 'L', 'R', 'L', 'R', 'B', 'A']
codeKeyValues = for key in code
switch key
when 'L' then 37
when 'U' then 38
when 'R' then 39
when 'D' then 40
when 'A' then 65
when 'B' then 66
console.log codeKeyValues
evens = (x for x in [2..10] by 2)
console.log evens
isInteger = (num) -> num is Math.round(num)
numsThatDivid960 = (num for num in [1..960] when isInteger(960 / num))
console.log numsThatDivid960
result:
[ -1, -2, -3, -4 ]
[ 'c', 'b', 'a' ]
[ 38, 38, 40, 40, 37, 39, 37, 39, 66, 65 ]
[ 2, 4, 6, 8, 10 ]
[ 1,
2,
3,
4,
5,
6,
8,
10,
12,
15,
16,
20,
24,
30,
32,
40,
48,
60,
64,
80,
96,
120,
160,
192,
240,
320,
480,
960 ]
code:
[firstName, middleInitial, lastName] = ['Joe', 'T', 'Plumber']
console.log firstName, middleInitial, lastName
newBoss = 'naki'
oldBoss = 'mike'
[newBoss, oldBoss] = [oldBoss, newBoss]
console.log newBoss, oldBoss
[theBest, theRest...] = ['naki', 'mike', 'youghee']
console.log theBest, theRest
myRect =
x: 100
y: 200
{x: myX, y: myY} = myRect
console.log 'myX: ', myX, 'myY: ', myY
{x, y} = myRect
console.log 'x: ', x, 'y: ', y
{ok, strictEqual} = require 'assert'
{languages: [favoriteLanguage, otherLanguages...]} = resume
result:
Joe T Plumber
mike naki
naki [ 'mike', 'youghee' ]
myX: 100 myY: 200
x: 100 y: 200
code:
root = global ? window
# file1.coffee
root.emergencyNumber = 911
# 글로벌 영역에 변수를 만들려면 root를 참조해야한다. (익명함수에 감싸져 있기때문.)
# file2.coffee
console.log emergencyNumber # '911'
emergencyNumber is root.emergencyNumber # true
code:
root = global ? window
# file1.coffee
root.dogName = 'Fido'
dogName is root.dogName # true
# file2.coffee
console.log dogName # undefined
# 이 파일 영역의 익명함수 맨 위에 var dogName; 이 선언되기 때문이다.
dogName = 'Bingo'
dogName is root.dogName # false
code:
Boy = ->
Boy::sing = -> console.log "It isn't easy being a boy named Sue"
# Boy.prototype.sing 을 의미한다.
# ::는 prototype 을 의미한다.
sue = new Boy()
sue.sing()
result:
It isn't easy being a boy named Sue
code:
Gift = (@name) ->
Gift.count++
@day = Gift.count
@announce()
Gift.count = 0
Gift::announce = ->
console.log "On day #{@day} of Christmas I received #{@name}"
gift1 = new Gift('a partridge in a pear tree')
gift2 = new Gift('two turtle doves')
result:
On day 1 of Christmas I received a partridge in a pear tree
On day 2 of Christmas I received two turtle doves
code:
Raven = ->
Raven::quoth = -> console.log 'Navermore'
raven1 = new Raven()
raven1.quoth()
Raven::quoth = -> console.log "I'm hungry"
raven1.quoth()
raven2 = new Raven()
raven2.quoth = -> console.log "I'm my own kind of raven"
raven1.quoth()
raven2.quoth()
console.log raven1.hasOwnProperty('quoth')
console.log raven2.hasOwnProperty('quoth')
result:
Navermore
I'm hungry
I'm hungry
I'm my own kind of raven
false
true
code:
class Tribble
constructor: ->
@isAlive = true
Tribble.count++
# Prototype properties
breed: -> new Tribble if @isAlive
die: ->
Tribble.count-- if @isAlive
@isAlive = false
# Class-level properties
@count: 0
@makeTrouble: -> console.log ('Trouble!' for i in [1..@count]).join(' ')
tribble1 = new Tribble()
tribble2 = new Tribble()
Tribble.makeTrouble()
tribble1.die()
Tribble.makeTrouble()
tribble2.breed().breed().breed()
Tribble.makeTrouble()
result:
Trouble! Trouble!
Trouble!
Trouble! Trouble! Trouble! Trouble!
code:
class Pet
constructor: -> @isHungry = true
eat: -> @isHungry = false
class Dog extends Pet
eat: ->
console.log '*crunch, crunch*'
super() # Pet::eat.call this
fetch: ->
console.log 'Yip yip!'
@isHungry = true
code:
class Appliance
constructor: (warranty) ->
warrantyDb.save(this) if warranty
class Toaster extends Appliance
constructor: (warranty) ->
super
# 생성자의 모든 인자를 전달하려면 간단하게 괄호 없는 super 를 사용하면 된다.
code:
class Shape
constructor: (@width) ->
computeArea: -> throw new Error('I am an abstract class!!')
class Square extends Shape
computeArea: -> Math.pow @width, 2
class Circle extends Shape
radius: -> @width / 2
computeArea: -> Math.PI * Math.pow @radius(), 2
showArea = (shape) ->
unless shape instanceof Shape
throw new Error('showArea requires a Shape instance!')
console.log shape.computeArea()
showArea new Square(2)
showArea new Circle(2)
result:
4
3.141592653589793
code:
requisitionStarship = (captain) ->
switch captain
when 'Kirk', 'Picard', 'Archer'
new Enterprise()
# 암묵적으로 처리가 중단된다
when 'Janeway'
new Voyager()
else
throw new Error('Invalid starship captain')
# switch의 결과가 반환된다.
code:
console.log switch 1
when 0
'0!!'
when 1
'1!!'
when 2
'2!!'
else
'invalidated value!!'
result:
1!!
code: index.html
<html>
<head>
<title></title>
<script type="text/javascript" src="coffee-script.js"></script>
<script type="text/javascript" src="jquery-1.5.2.min.js"></script>
<script type="text/coffeescript" src="Dictionary.coffee"></script>
<link rel="stylesheet" type="text/css" href="./style.css" />
</head>
<body>
</body>
</html>
code: Dictionary.coffee
root = exports ? window
# node.js 라면 exports, 브라우저라면 window
root.Dictionary = Dictionary
...
code: first.coffee
exports.greet = ->
console.log "I'm first.coffee!!"
code: second.js
var CoffeeScript = require('coffee-script');
CoffeeScript.register();
// or require('coffee-script/register');
var greet = require('./first').greet;
greet();
result:
I'm first.coffee!!