Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

CoffeeScript의 기본적인 문법과 Function

커피스크립트는 자바스크립트로 컴파일되는 Transpiler이기 때문에 더 적은 코드를 통해서 읽기 쉽고, 작성하기 쉽고 수정하기 쉬운 코드를 통해서 동일한 자바스크립트의 기능을 구현하는 것이 목적이기 때문에 그외에 추가적인 부분은 제공하고 있지 않습니다. 다시 말하면 축약형 코드나 읽기 좋은 단순한 문법으로 작성할 수 있는 언어레벨의 기능은 제공하고 있지만 일반적인 라이브러리나 프레임워크처럼 추가적인 기능들(그래픽적인 부분이라든가 ajax에 대한 처리라든가 하는)등은 제공하고 있지 않습니다. 그런 면에서 커피스크립트는 HTML을 위한 HAML이나 CSS를 위한 SASS와 유사하다고 할 수 있습니다.

커피스크립트로 코드를 작성하면 컴파일러가 자바스크립트 베스트 프렉티스에 맞춰진 좋은 코드를 만들어줍니다. 커피스크립트를 사용한다고 해서 프로젝트의 모든 자바스크립트를 자바스크립트로 작성해야 하는 것은 아니기 때문에 필요한 부분만 커피스크립트로 작성해서 섞어 사용할 수 있습니다.

커피스크립트의 코드를 보면 마치 파이썬이나 루비같은 느낌이 듭니다. 아마 커피스크립트를 만든 Jeremy는 자바스크립트를 루비나 파이썬처럼 작성하고 싶어서 만든 것인지는 모르겠습니다. 파이썬이나 루비를 사용해 보았다면 아마 코드가 상당히 친숙하게 느껴질 것이고 그렇지 않다면 오히려 이해하기 난해한 코드처럼 보일수도 있지만 코드의 양을 많이 줄일 수 있기 때문에 익숙해 지고 난 후에는 꽤 편리하고 빠르게 작성할 수 있을 것 같습니다. 문법부터 보겠습니다. 커피스크립트 문법의 아웃풋이 보고싶다면 공식페이지의 TRY COFFEESCRIPT에서 확인하시면 됩니다.


Function
커피스크립트에서 함수 정의는 -> 기호를 사용합니다.

-> console.log 'Hello World'


(function() {
  return console.log('Hello World');
});

위는 커피스크립트이고 아래는 컴파일된 자바스크립트입니다.(아래헤서도 컴파일 결과가 필요할때는 2가지 코드블럭을 연속으로 사용하겠습니다.) 이렇게 작성된 함수는 아래처럼 do명령어를 이용하거나 ()를 이용해서 실행할 수 있습니다.(두 코드는 동일한 코드입니다.)

do -> console.log 'Hello World'
(-> console.log 'Hello World')()

또한 리턴문은 자동으로 함수에서 실행된 마지막 표현식의 결과가 리턴값이 되기 때문에 명시적으로 return문을 사용하지 않아도 됩니다.(물론 필요하다면 사용할 수 있습니다.)
함수에 이름을 주려면 변수에 할당해야 합니다.

greeting = -> console.log 'Hello World'


var greeting;
greeting = function() {
  return console.log('Hello World');
};

커피스크립트에서는 세미콜론(;), 괄호(), 중괄호{}는 생략할 수 있습니다. (괄호의 경우는 파라미터에서는 생략할 수 없고 중괄호는 JSON스타일의 객체를 선언할때만 사용합니다.)

파라미터가 있는 함수의 경우 아래와 같이 정의할 수 있습니다.

greeting = (msg) -> console.log 'Hello ' + msg


var greeting;
greeting = function(msg) {
  return console.log('Hello ' + msg);
};

함수에서 문자열을 이어붙히는 부분은 아래와 같이 사용할 수도 있습니다.

greeting = (msg) -> console.log "Hello #{msg}"

+ 를 이용한 컨테트네이션(concatenation) 대신에 쌍따옴표(")를 사용할 일 경우에는 #{변수명}의 형식으로 EL(Expression Language)처럼 작성할 수도 있습니다. '와 "외에도 파이썬과 유사한 """와 '''로도 문자열을 정의할 수 있으며 이는 heredoc 문자열이라고 부르는데 이는 문자열을 여러라인에 걸쳐서 작성할 수 있게 해줍니다. """와 '''의 차이점은 앞에서와 유사하게 #{}를 사용할 수 있는냐 아니냐의 차이만 있을 뿐입니다.

+ 오퍼레이터는 공백에 따라 동작이 달라집니다. 예를 들어, 다음과 같습니다.

a = 'outsider'
a + 2011 # work
a +2011 # TypeError

위와 같이 사용할 경우 2번라인은 a + 2011;로 컴파일이 되지만 3번라인은 a(+2011);로 컴파일이 되기 때문에 타입오류가 발생합니다. 변수가 아닌 'outsider' +2011 같이 작성한 경우는 타입오류가 발생하지 않습니다.


범위(Scope)
커피스크립트에는 범위에 대한 다음 3가지 규칙이 있습니다.

  1. 모든 함수는 범위를 만들며 범위를 만드는 유일한 방법은 함수를 정의하는 것입니다.
  2. 변수는 변수가 할당된 곳에서 최상단에서 존재하게 됩니다.
  3. 범위 바깥에서는 변수에 접근할 수 없습니다.
이 접근은 lexical scope라고 알려져있으며 명시적으로 var를 사용하는 것외에는 자바스크립트와 동일합니다. 커피스크립트에서는 별도의 변수의 정의가 존재하지 않으며(var a;같은) 변수에 할당을 통해서 변수가 정의되게 됩니다.


그 밖의 문법

오퍼레이터

  • is : ===
  • isnt : !==
  • not : !
  • and : &&
  • or : ||
  • true, yes, on : ture
  • false, no, off : false
조건문
if true
  1
else if false
  2

조건문은 위와 같이 사용할 수 있고 내부 블럭은 중괄호를 사용하는 대신에 들여쓰기를 통해서 구분해 줄 수 있습니다.

if true then 1
1 if true
if true then 1 else 2
1 unless true
unless true then 1

위에 나온 예시 코드들처럼 조건문을 한줄로도 작성할 수 있으며 unless는 if not의 별칭입니다.


존재확인 오퍼레이터
그 외 존재여부를 확인하는 Existential 오퍼레이터가 있으며 ?를 사용합니다. ?를 사용할 경우 주어진 값이 현재 범위에서 있으면서 undefined나 null이 아닌지를 체크해 줍니다. 예를 들어 a ? b 와 같이 작성하면 a가 존재하면 a를 리턴하고 a가 존재하지 않으면 b를 리턴합니다. a ?= b 는 a = b unless a?와 동일합니다. 추가적으로 a.b를 사용할 경우에 a가 null일 경우에는 오류가 발생하게 되는데 a = b if a? 와 작성하는 대신에 a?.b로 간단하게 작성할 수 있습니다. 이는 Existential chain operator로 보통 Soak로 알려져 있습니다.


this와 =>
@는 this의 별칭입니다. 컨텍스트에 할당하려면 ->대신에 =>를 사용할 수 있으며 이는 bound function operator나 fat arrow라고 부릅니다.

callback -> 1


callback(function() {
  return 1;
});

-> 로 함수를 사용할 경우 위처럼 컴파일 되지만 => 를 사용하면 아래와 같이 컴파일됩니다.

callback => 1


var __bind = function(fn, me){ 
  return function(){
    return fn.apply(me, arguments); 
  }; 
};
callback(__bind(function() {
  return 1;
}, this));

=>는 this를 현재의 컨텍스트에 고정해야할 때 유용합니다. 자바스크립트에서는 this가 호출되는 context에 따라 달라지는데 이벤트 리스너같은 경우에는 현재의 컨텍스트를 이용해야 하기 때문에 보통 this를 _self같은 변수에 담아두고 사용하게 되는에 이럴때 =>로 함수를 정의하면 현재 컨텍스트로 this가 고정되게 됩니다.


프로퍼티
객체의 프로퍼티를 할당하는 setter같은 경우

setName = (name) -> @name = name

위와 같이 사용할 수 있는데 아래와 같이 간단히 사용할 수 있습니다.

setName = (@name) ->

파라미터에 @를 쓸 경우 같은 이름의 변수에 전달받은 값을 할당할 수 있으며 여러개의 파라미터일 때도 섞어서 사용할 수 있습니다.


파라미터의 기본값
파라미터에 기본값이 있는 경우는 보통 전달받은 파라미터가 있는지를 검사하고 없을 경우에 기본값을 할당하게 작성하는데 아래와 같이 간단하게 작성할 수 있습니다.

(a = true) -> 

위와 같은 경우 a가 전달되지 않으면 true로 할당되고 전달되면 전달된 파라미터값으로 a가 할당됩니다.


Splat(...)
커피스크립트는 Splat이라고 부르는 ...기호를 사용해서 아규먼트의 범위를 자동으로 배열로 변환합니다.

a = (b, c...) -> console.log c
a 1, 2, 3, 4, 5

위와 같이 작성하면 [2, 3, 4, 5]의 결과가 나옵니다. Splat은 파라미터의 갯수가 고정되어 있지 않고 동적인 경우에 자동으로 배열로 변환되어 받을 수 있습니다. 위 예제에서 b에는 1이 할당되고 c에는 나머지 파라미터인 2,3,4,5가 배열로 담긴 것입니다.

a = [1,2,3,4,5]
[b..., c] = a

왼쪽에 있는 [b..., c]는 배열이 아닌 패턴매칭이고 우측의 배열이 담기게 되는데 여기서도 Splat를 사용할 수 있습니다. 위의 소스에서 변수 b에 [1,2,3,4]가 할당되고 변수 c에는 5가 할당됩니다. 위에서 본 것 처럼 Splat는 배열의 마지막에만 사용하는 것이 아닌 어느 위치에서나 사용할 수 있습니다.

a = [1,2,3,4,5]
[b, c..., d] = a

위와같이 가운데에도 Splat를 사용할 수 있습니다. b는 1이 되고 d는 5가 되고 나머지인 [2,3,4]가 c에 할당됩니다. Splat이 사용되지 않은 나머지 파라미터들이 모두 할당되고 나머지 파라미터들이 Splat에 할당됩니다. 당연한 이야기이지만 Splat는 2개를 같이 사용할 수는 없습니다.

또한 Splat는 함수내에서 사용하면 앞에서 본것처럼 배열로 압축하는 것이 아닌 배열을 확장해 주게 됩니다.

coffee> a = [1, 2, 3]
coffee> console.log a
[ 1, 2, 3 ]
coffee> console.log a...
1 2 3

위의 예제는 Splat을 함수내에서 사용했을때의 결과입니다.


주석
주석은 # 기호를 사용하고 컴파일 결과에는 나타나지 않습니다.
2011/08/13 00:43 2011/08/13 00:43