Coffee Script 소개
- CoffeeScript 는 컴파일하면 JavaScript 가 되는 작은 규모의 언어.
- JavaScript의 라이브러리를 가져다 쓸 수도 있다.
- 컴파일시에는 JavaScript Lint 를 통해 컴파일되기 때문에 안정성 측면에서 좋다.
- CoffeeScript 로 작업하면 보통 자바스크립트 코드보다 빠를수도 있다. ( 최적화 코드로 치환되며 실수가 적어져서 )
설치와 사용
- CoffeeScript 의 컴파일러 "coffee" 는 Node.js 의 유틸로서 사용할 수 있다. 하지만 사실 CoffeeScript 자체가 Node.js 에 의존하고 있는 것은 아니다.
> coffee -c test.coffee
> coffee
언어적 특성
- 커피스크립트는 스페이스바 공백을 block 구분하는 데 쓴다.
- 세미콜론( ; ) 을 사용할 필요는 없다.
- { } 대신 들여쓰기로 그 기능을 대신한다.
- 파라미터를 전달하는 function call시 () 도 필요없다. 공백 한칸을 주고 파라미터를 주면 바로 () 의 역할을 한다. ( 파라미터가 없는 경우에는 함수임을 표시하기 위해 () 가 필요하다. 일관성을 위해서 항상 () 써주는 것도 한 방법이다. )
Function
변수 = (파라미터, 파라미터...) -> 내용물
<함수 기본>
square = (x) -> x * x
cube = (x) -> square(x) * x
var cube, square;
square = function(x) {
return x * x;
};
cube = function(x) {
return square(x) * x;
};
<파라미터 기본값 설정>
fill = (container, liquid = "coffee") ->
"Filling the #{container} with #{liquid}..."
var fill;
fill = function(container, liquid) {
if (liquid == null) {
liquid = "coffee";
}
return "Filling the " + container + " with " + liquid + "...";
};
Objects and Arrays
- 기본 스크립트와 매우 비슷하다.
- comma 로 인한 구분은 option.
- reserved key 를 string 화 할 필요 없이 사용할 수 있다. coffee script 가 자동으로 이런 녀석들을 quotation 처리한다.
<Object & Array 기본>
song = ["do", "re", "mi", "fa", "so"]
singers = {Jagger: "Rock", Elvis: "Roll"}
bitlist = [
1, 0, 1
0, 0, 1
1, 1, 0
]
kids =
brother:
name: "Max"
age: 11
sister:
name: "Ida"
age: 9
var bitlist, kids, singers, song;
song = ["do", "re", "mi", "fa", "so"];
singers = {
Jagger: "Rock",
Elvis: "Roll"
};
bitlist = [1, 0, 1, 0, 0, 1, 1, 1, 0];
kids = {
brother: {
name: "Max",
age: 11
},
sister: {
name: "Ida",
age: 9
}
};
<Reserved Key Case>
$('.account').attr class: 'active'
log object.class
$('.account').attr({
"class": 'active'
});
log(object["class"]);
Lexical Scoping and Variable Safety
- 명시적으로 var 를 사용할 수 없다.
- -> 는 함수정의라는 의미.
- 변수는 무조건 최상단에 정의된다. 같은 이름을 inner & outer function 에서 사용할 경우 scope 에 주의해야 한다.
- 모든 CoffeeScript 의 output 은 (function(){…}(); 의 형태로 wrap 되어 나온다.
- 만약 global 로 만들고 싶다면, window 에 정의하거나, exports 를 이용하여 export 시켜준다. ( exports ? this 로 접근 )
outer = 1
changeNumbers = ->
inner = -1
outer = 10
inner = changeNumbers()
var changeNumbers, inner, outer;
outer = 1;
changeNumbers = function() {
var inner;
inner = -1;
return outer = 10;
};
inner = changeNumbers();
If, Else, Unless, and Conditional Assignment
- 조건문류는 {} 없이 들여쓰기로 구분된다.
- if 나 unless 등은 구문 앞에 올수도, 뒤에 올 수도 있다.
mood = greatlyImproved if singing
if happy and knowsIt
clapsHands()
chaChaCha()
else
showIt()
date = if friday then sue else jill
var date, mood;
if (singing) {
mood = greatlyImproved;
}
if (happy && knowsIt) {
clapsHands();
chaChaCha();
} else {
showIt();
}
date = friday ? sue : jill
Splats.
- … 을 이용하여 임의적으로 추가되는 variable 들을 받을 수 있다.
gold = silver = rest = "unknown"
awardMedals = (first, second, others...) ->
gold = first
silver = second
rest = others
contenders = [
"Michael Phelps"
"Liu Xiang"
"Yao Ming"
"Allyson Felix"
"Shawn Johnson"
"Roman Sebrle"
"Guo Jingjing"
"Tyson Gay"
"Asafa Powell"
"Usain Bolt"
]
awardMedals contenders... // parameter 전달시에도 ... 이 필요하다. argument 그대로 채우지 않을 경우는.
alert "Gold: " + gold
alert "Silver: " + silver
alert "The Field: " + rest
var awardMedals, contenders, gold, rest, silver,
__slice = [].slice;
gold = silver = rest = "unknown";
awardMedals = function() {
var first, others, second;
first = arguments[0], second = arguments[1], others = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
gold = first;
silver = second;
return rest = others;
};
contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"];
awardMedals.apply(null, contenders);
alert("Gold: " + gold);
alert("Silver: " + silver);
alert("The Field: " + rest);
Loops and Comprehensions
- 일반 구문은 가장 최후의 결과를 return 한다.
- [0..10] 과 같은 구문으로 범위설정도 가능하다.
- 범위설정시 step 을 by 로 설정 가능하다.
- 값 가져오는 것은 #{variable} 로.
- of 를 이용하여 json 에 접근.
- while 은 low-level 로 제공.
- until 은 while not 과 같다.
- do는 argument 를 전달하여 바로 function 실행.
<일반 loop & for in 문>
# Eat lunch.
eat food for food in ['toast', 'cheese', 'wine']
# Fine five course dining.
courses = ['greens', 'caviar', 'truffles', 'roast', 'cake']
menu i + 1, dish for dish, i in courses
// 햇갈리는 구문. 문법처럼 외우면 되겠다. in 전에 2개의 param 이 오면 첫번째가 assign, 두번째가 index
# Health conscious meal.
foods = ['broccoli', 'spinach', 'chocolate']
eat food for food in foods when food isnt 'chocolate'
var courses, dish, food, foods, i, _i, _j, _k, _len, _len1, _len2, _ref;
_ref = ['toast', 'cheese', 'wine'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
food = _ref[_i];
eat(food);
}
courses = ['greens', 'caviar', 'truffles', 'roast', 'cake'];
for (i = _j = 0, _len1 = courses.length; _j < _len1; i = ++_j) {
dish = courses[i];
menu(i + 1, dish);
}
foods = ['broccoli', 'spinach', 'chocolate'];
for (_k = 0, _len2 = foods.length; _k < _len2; _k++) {
food = foods[_k];
if (food !== 'chocolate') {
eat(food);
}
}
<..을 통한 범위지정>
countdown = (num for num in [10..1])
var countdown, num;
countdown = (function() {
var _i, _results;
_results = [];
for (num = _i = 10; _i >= 1; num = --_i) {
_results.push(num);
}
return _results;
})();
<of 문>
yearsOld = max: 10, ida: 9, tim: 11
ages = for child, age of yearsOld
"#{child} is #{age}"
// of 전에 parameter 는 key 가 되고 of 의 내용물을 value 가 되는 형태
var age, ages, child, yearsOld;
yearsOld = {
max: 10,
ida: 9,
tim: 11
};
ages = (function() {
var _results;
_results = [];
for (child in yearsOld) {
age = yearsOld[child];
_results.push("" + child + " is " + age);
}
return _results;
})();
<while & until 문>
# Econ 101
if this.studyingEconomics
buy() while supply > demand
sell() until supply > demand
# Nursery Rhyme
num = 6
lyrics = while num -= 1
"#{num} little monkeys, jumping on the bed.
One fell out and bumped his head."var lyrics, num;
if (this.studyingEconomics) {
while (supply > demand) {
buy();
}
while (!(supply > demand)) {
sell();
}
}
num = 6;
lyrics = (function() {
var _results;
_results = [];
while (num -= 1) {
_results.push("" + num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
}
return _results;
})();
< do 문 >
for filename in list
do (filename) ->
fs.readFile filename, (err, contents) ->
compile filename, contents.toString()
// do 다음에 오는 function에 대해 param을 looping 돌려 적용하는데 좋다.
var filename, _fn, _i, _len;
_fn = function(filename) {
return fs.readFile(filename, function(err, contents) {
return compile(filename, contents.toString());
});
};
for (_i = 0, _len = list.length; _i < _len; _i++) {
filename = list[_i];
_fn(filename);
}
Array Slicing and Splicing with Ranges
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
start = numbers[0..2]
middle = numbers[3...6]
end = numbers[6..]
copy = numbers[..]
var copy, end, middle, numbers, start;
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
start = numbers.slice(0, 3);
middle = numbers.slice(3, 6);
end = numbers.slice(6);
copy = numbers.slice(0);
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
numbers[3..6] = [-3, -4, -5, -6]
var numbers, _ref;
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
[].splice.apply(numbers, [3, 4].concat(_ref = [-3, -4, -5, -6]));
Everything is an Expression( at least, as much as possible )
- Coffee Script 의 모든 function 은 return 이 있다.
- 의도적으로 return 을 사용할 수도 있다.
- try catch 문도 모두 return 한다. ( try… catch error … )
<function return>grade = (student) ->
if student.excellentWork
"A+"
else if student.okayStuff
if student.triedHard then "B" else "B-"
else
"C"
eldest = if 24 > 21 then "Liz" else "Ike"
var eldest, grade;
grade = function(student) {
if (student.excellentWork) {
return "A+";
} else if (student.okayStuff) {
if (student.triedHard) {
return "B";
} else {
return "B-";
}
} else {
return "C";
}
};
eldest = 24 > 21 ? "Liz" : "Ike";
<variable assignment>
six = (one = 1) + (two = 2) + (three = 3)
var one, six, three, two;
six = (one = 1) + (two = 2) + (three = 3);
<range>
# The first ten global properties.
globals = (name for name of window)[0...10]
var globals, name;
globals = ((function() {
var _results;
_results = [];
for (name in window) {
_results.push(name);
}
return _results;
})()).slice(0, 10);
<try - catch 문>
alert(
try
nonexistent / undefined
catch error
"And the error is ... #{error}"
)
alert((function() {
try {
return nonexistent / void 0;
} catch (error) {
return "And the error is ... " + error;
}
})());
Operators and Aliases
CoffeeScript | JavaScript |
---|---|
is | === |
isnt | !== |
not | ! |
and | && |
or | || |
true, yes, on | true |
false, no, off | false |
@, this | this |
of | in |
in | no JS equivalent |
launch() if ignition is on
volume = 10 if band isnt SpinalTap
letTheWildRumpusBegin() unless answer is no
if car.speed < limit then accelerate()
winner = yes if pick in [47, 92, 13]
print inspect "My name is #{@name}"
var volume, winner;
if (ignition === true) {
launch();
}
if (band !== SpinalTap) {
volume = 10;
}
if (answer !== false) {
letTheWildRumpusBegin();
}
if (car.speed < limit) {
accelerate();
}
if (pick === 47 || pick === 92 || pick === 13) {
winner = true;
}
print(inspect("My name is " + this.name));
The Existential Operator
- existence 는 ? operator 로 check 가능하다. zero, empty string, false, null, undefined 모두를 검사한다.
- ?.는 chain 일 때 사용한다.
- if val? 은 variable 이 null 이 아닐 경우를 의미.
- ?= 는 null 이면 대입하라는 의미
- result = val1? val2 는 val1이 null이 아니면 val1 이고 아니면 val2 라는 의미.
solipsism = true if mind? and not world?
speed = 0
speed ?= 15
footprints = yeti ? "bear"
var footprints, solipsism, speed;
if ((typeof mind !== "undefined" && mind !== null) && !(typeof world !== "undefined" && world !== null)) {
solipsism = true;
}
speed = 0;
if (speed == null) {
speed = 15;
}
footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";
< ?문의 chain 사용>
zip = lottery.drawWinner?().address?.zipcode
var zip, _ref;
zip = typeof lottery.drawWinner === "function" ? (_ref = lottery.drawWinner().address) != null ? _ref.zipcode : void 0 : void 0;
Classes, Inheritance, and Super
- Coffee Script 에서는 class 의 개념 있음. super 도 지정할 수 있고, constructor 를 지정할 수도 있다.
- :: 로는 object의 prototype 에 바로 접근할 수 있다.
- Class definition 에서의 this 는 class object 자신이기 때문에, static property 는 @property: value 를 통해 접근할 수 있다.
<class definition>
class Animal
constructor: (@name) ->
// constructor 의 (@name)-> 단순 값 assign. 즉 this.name = name;
move: (meters) ->
alert @name + " moved #{meters}m."
class Snake extends Animal
move: ->
alert "Slithering..."
super 5
class Horse extends Animal
move: ->
alert "Galloping..."
super 45
sam = new Snake "Sammy the Python"
tom = new Horse "Tommy the Palomino"
sam.move()
tom.move()
var Animal, Horse, Snake, sam, tom,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) {
for (var key in parent) {
if (__hasProp.call(parent, key))
child[key] = parent[key];
}
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
return child;
};
Animal = (function() {
function Animal(name) {
this.name = name;
}
Animal.prototype.move = function(meters) {
return alert(this.name + (" moved " + meters + "m."));
};
return Animal;
})();
Snake = (function(_super) {
__extends(Snake, _super);
function Snake() {
return Snake.__super__.constructor.apply(this, arguments);
}
Snake.prototype.move = function() {
alert("Slithering...");
return Snake.__super__.move.call(this, 5);
};
return Snake;
})(Animal);
Horse = (function(_super) {
__extends(Horse, _super);
function Horse() {
return Horse.__super__.constructor.apply(this, arguments);
}
Horse.prototype.move = function() {
alert("Galloping...");
return Horse.__super__.move.call(this, 45);
};
return Horse;
})(Animal);
sam = new Snake("Sammy the Python");
tom = new Horse("Tommy the Palomino");
sam.move();
tom.move();
<Prototype access>
String::dasherize = ->
this.replace /_/g, "-"
String.prototype.dasherize = function() {
return this.replace(/_/g, "-");
};
Destructuring Assignment.
<Switching assignment>
theBait = 1000
theSwitch = 0
[theBait, theSwitch] = [theSwitch, theBait]
var theBait, theSwitch, _ref;
theBait = 1000;
theSwitch = 0;
_ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1];
<Array Assignment>
weatherReport = (location) ->
# Make an Ajax request to fetch the weather...
[location, 72, "Mostly Sunny"]
[city, temp, forecast] = weatherReport "Berkeley, CA"
var city, forecast, temp, weatherReport, _ref;
weatherReport = function(location) {
return [location, 72, "Mostly Sunny"];
};
_ref = weatherReport("Berkeley, CA"), city = _ref[0], temp = _ref[1], forecast = _ref[2];
<Structural assignment>
futurists =
sculptor: "Umberto Boccioni"
painter: "Vladimir Burliuk"
poet:
name: "F.T. Marinetti"
address: [
"Via Roma 42R"
"Bellagio, Italy 22021"
]
{poet: {name, address: [street, city]}} = futurists
var city, futurists, name, street, _ref, _ref1;
futurists = {
sculptor: "Umberto Boccioni",
painter: "Vladimir Burliuk",
poet: {
name: "F.T. Marinetti",
address: ["Via Roma 42R", "Bellagio, Italy 22021"]
}
};
_ref = futurists.poet, name = _ref.name, (_ref1 = _ref.address, street = _ref1[0], city = _ref1[1]);
<Splates assignment>
tag = "<impossible>"
[open, contents..., close] = tag.split("")
var close, contents, open, tag, _i, _ref,
__slice = [].slice;
tag = "<impossible>";
_ref = tag.split(""), open = _ref[0], contents = 3 <= _ref.length ? __slice.call(_ref, 1, _i = _ref.length - 1) : (_i = 1, []), close = _ref[_i++];
Function binding
- function 을 callback 으로 붙이거나, 다른 object 에 attach 하는 경우 정의할 당시의 this context 는 날아갈 수 있다.
- => 는 function define 은 물론 현재의 this(context) 도 함께 전달한다.
- -> 는 => 와 다르다.
<Context delivering with =>>
Account = (customer, cart) ->
@customer = customer
@cart = cart
$('.shopping_cart').bind 'click', (event) =>
@customer.purchase @cart
var Account;
Account = function(customer, cart) {
var _this = this;
this.customer = customer;
this.cart = cart;
return $('.shopping_cart').bind('click', function(event) {
return _this.customer.purchase(_this.cart);
});
};
Embedded JavaScript
- ' ' 안에 써서 assign 하면 compile될 때 conversion 없이 script 언어 그대로가 들어간다.
hi = `function() {
return [document.title, "Hello JavaScript"].join(": ");
}`
var hi;
hi = function() {
return [document.title, "Hello JavaScript"].join(": ");
};
Switch/When/Else
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
switch (day) {
case "Mon":
go(work);
break;
case "Tue":
go(relax);
break;
case "Thu":
go(iceFishing);
break;
case "Fri":
case "Sat":
if (day === bingoDay) {
go(bingo);
go(dancing);
}
break;
case "Sun":
go(church);
break;
default:
go(work);
}
Try/Catch/Finally
try
allHellBreaksLoose()
catsAndDogsLivingTogether()
catch error
print error
finally
cleanUp()
try {
allHellBreaksLoose();
catsAndDogsLivingTogether();
} catch (error) {
print(error);
} finally {
cleanUp();
}
Chained Comparisons
cholesterol = 127
healthy = 200 > cholesterol > 60
var cholesterol, healthy;
cholesterol = 127;
healthy = (200 > cholesterol && cholesterol > 60);
String Interpolation, Block String, and Block Comments
- #{…} 내용은 "" 안에서 수식으로 인정된다. ( 변수를 링크할 떄에도 사용 )
- 멀티라인 string은 그냥 string으로 인식.
- 형식을 맞춘 string 이 필요하다면 """ 내용 """ 으로 한다.
- ### 내용 ### 는 블럭 커멘트
< #{ expression } >
author = "Wittgenstein"
quote = "A picture is a fact. -- #{ author }"
sentence = "#{ 22 / 7 } is a decent approximation of π"
var author, quote, sentence;
author = "Wittgenstein";
quote = "A picture is a fact. -- " + author;
sentence = "" + (22 / 7) + " is a decent approximation of π";
loadrun: sentence
<String interpolation>
html = """
<strong>
cup of coffeescript
</strong>
"""
var html;
html = "<strong>\n cup of coffeescript\n</strong>";
<Block Comment>
###
CoffeeScript Compiler v1.3.3
Released under the MIT License
###
/*
CoffeeScript Compiler v1.3.3
Released under the MIT License
*/
Block Regular Expressions
- regular expression 은 /// 으로 시작한고, ///로 끝난다.
OPERATOR = /// ^ (
?: [-=]> # function
| [-+*/%<>&|^!?=]= # compound assign / compare
| >>>=? # zero-fill right shift
| ([-+:])\1 # doubles
| ([&|<>])\2=? # logic / shift
| \?\. # soak access
| \.{2,3} # range or splat
) ///
var OPERATOR;
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
load
Cake and Cakefiles
- Cake 는 빌드 시스템. Cakefile 에 빌드에 대한 내용이 들어있다. cake [task] 를 통해 빌드를 실행할 수 있다. ( 단순 컴파일은 coffee 로 )
"text/coffeescript" Script Tags
- <script type="text/coffeescript"> 를 통해 browser 에 직접적으로 coffeescript 태그도 들어갈 수 있다. 하지만 이 녀석은 컴파일을 위해 coffee-script.js 를 필요로 한다. 속도 및 메모리를 고려했을 떄 ( 특히 모바일 환경에서는 ) js 로 compile 된 녀석을 사용하는 것이 훨씬 좋다.
'프로그래밍 놀이터 > Web' 카테고리의 다른 글
[Script] JavaScript Prototype 과 상속 제대로 이해하기 (6) | 2012.09.24 |
---|---|
[Script] CORDOVA 란? (2) | 2012.09.23 |
[Script] Handlebars example or sample code ( 샘플 코드 ) (0) | 2012.09.22 |
[Script] Handlebars Tutorial & Reference (0) | 2012.09.21 |
[Script] CSS3 Reference (0) | 2012.09.21 |
댓글