Table Of Contents

This Page

ご注文はCoffeeScriptですか? ~CoffeeScript入門~

まえがき

こんにちは。3回生のはるさめです。皆さんはCoffeeScriptというプログラミング言語を聞いたことがあるでしょうか?

CoffeeScriptとは、JavaScriptに変換することができる言語です。 JavaScriptはWebブラウザなどが実行できるスクリプトであり、Webサイトでは広く使われています。 やがて、Ajaxなどの技術が普及し、Webサイトで用いられるJavaScriptはどんどん複雑になってきたため、 素のJavaScriptを使いやすくするために、jQueryなどのライブラリが使われるようになりました。

しかし、jQueryなどの便利ツール自体もJavaScriptを使っているので、JavaScript自体の言語仕様から逃れることはできません。 JavaScriptという 足枷 がある限り、そこから柵を越えることなどできないのです。

CoffeeScriptによって、そんな制限から解放され、より素早くJavaScriptを書くことが出来るようになります。 CoffeeScriptはJavaScriptに変換される言語なので、JavaScriptに出来ないことをCoffeeScriptで出来るわけではないですが、 JavaScriptに出来ることをCoffeeScriptは 簡単に 行います。

インストール

CoffeeScriptを使う手っ取り早い方法はNode.jsを使う方法です。 Node.jsのサイト (http://nodejs.org) からまずはNode.jsをインストールします。

インストールが終わったら、Node.jsのパッケージ管理ツールであるnpmがすでに入っているので、npmでCoffeeScriptをインストールします。

$ sudo npm install coffee-script

これでインストールは終わりです。coffeeとコマンドを打つと対話的にCoffeeScriptを実行できます。

$ coffee
coffee> test = 'Hello, World!'
coffee> console.log test
Hello, World!

coffeeコマンドには自動コンパイル機能もあります。

$ coffee -w *.coffee -o js

と打つとそのフォルダを監視し、coffee拡張子のファイルが変更されると自動的にコンパイルしてjsフォルダに保存されます。

基本の文法

CoffeeScriptの公式サイト (http://coffeescript.org) には、ここで説明するまでもないほど丁寧に文法が説明されてますが、ここでも簡単に説明します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 変数宣言にvarは不要。;も不要
order = "rabbit"

# オブジェクト作成時に{}はいりません。改行すると,も不要
character =
    Cocoa:
        color:  "wheat"
        cv:     "Ayane Sakura"
    Chino:
        color:  "lavendar"
        cv:     "Inori Minase"
    Rize:
        color:  "purple"
        cv:     "Saya Taneda"

# ?で存在するかどうかを確認
console.log character.Rize.cv if character.Rize?

# !や===は使わない
cocoa = character.Cocoa
if cocoa.color is "wheat" and cocoa.cv isnt "Maaya Uchida"
    console.log "Yes, She is Cocoa!"

# for文が簡潔に書ける
for drink in ["Latte", "Cappuccino", "Caffè mocha"]
    # ""で囲った文字列は、#{...}で変数展開できる
    console.log "#{number} #{drink}, please." for number in [1..5]

# Javascriptのinは、CoffeeScriptではofになるので注意!
for name, data of character
    console.log "#{name} has #{data.color} hair."

CoffeeScriptの大きな特徴に、function-> と書ける機能があります。 JavaScriptの関数には第一級関数という機能があり、機能が複雑化していくとfunctionを入力しまくることになるのですが、 CoffeeScriptでは8文字から2文字まで大きく簡略化することができます。

さらに、インデントを用いることで中括弧も省略でき、丸括弧も自明であれば省略することができます。 この省略は見た目上でも大きなメリットになります。

1
2
3
$(function() {
    // JavaScriptでこのように書いていたのが
});
1
2
$ ->
    # CoffeeScriptではここまで省略できる!

クラス

CoffeeScriptではなんとJavaScriptには無いクラスが使えます。 JavaScriptはプロトタイブベースの言語と言われており、クラスの代わりにプロトタイプという別の概念によってオブジェクトを扱うのですが、 これは普段C#やJavaのようなクラスベースの言語を扱っている人にとっては、なかなか取っつきにくいものになっています。

CoffeeScriptはこのプロトタイプの機能を用いることで、継承など他の言語のクラスが使える基本的な機能を実現しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Restaurant
    constructor: (@name) ->
        @name = name                        # この文は省略可

    explain: ->
        "#{@name} serves food"

class CoffeeShop extends Restaurant
    explain: ->
        super() + "and coffee"

restaurant = new Restaurant "Kantoan"
coffeeshop = new CoffeeShop "Rubbit House"
console.log restaurant.explain()            # Kantoan serves food
console.log coffeeshop.explain()            # Rubbit House serves food and coffee

他の言語でクラスを扱ったことがあれば、だいたいの意味は分かると思います。 クラスの内部にある explain: -> は、クラスのインスタンスメソッドになります。 ここで constructor という名前のメソッドを作成すると、クラスのインスタンスが作成される際にそのメソッドが呼び出されるようになります。 つまり、 new Restauran "Kantoan" と呼び出した時点で、 this.name = "Kantoan" が自動的に実行されるのです。 このとき、変数の頭についている@マークは this. と等価です。

また、 class B extends A とすることで、BはAのメソッドを継承しますが、同じ名前のメソッドを作成することで、 親のメソッドをオーバーライドしたり、 super で親のメソッドを呼び出したりできます。 ここでは、superで "#{@name} serves food" を呼び出し "and coffee" と結合しています。

これをJavaScriptに変換すると、以下のようになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var CoffeeShop, Restaurant, coffeeshop, restaurant,
  __extends = function(child, parent) { ... };

Restaurant = (function() {
  function Restaurant(name) {
    this.name = name;
  }

  Restaurant.prototype.explain = function() {
    return "" + this.name + " serves food";
  };

  return Restaurant;

})();

CoffeeShop = (function(_super) {
  __extends(CoffeeShop, _super);

  function CoffeeShop() {
    return CoffeeShop.__super__.constructor.apply(this, arguments);
  }

  CoffeeShop.prototype.explain = function() {
    return CoffeeShop.__super__.explain.apply(this, arguments) + " and coffee";
  };

  return CoffeeShop;

})(Restaurant);

restaurant = new Restaurant("Kantoan");
coffeeshop = new CoffeeShop("Rubbit House");
console.log(restaurant.explain());
console.log(coffeeshop.explain());

関数__extendsの中身は省略しましたが、これを行うことによりCoffeeShop.__super__がRestaurant.prototypeを参照するようになります。 このようにCoffeeScriptではJavaScriptの機能を上手く使いクラスを作成することができます。


上の例ではクラス内でメソッドを宣言する際に : を使っていましたが、代わりに = を使用するとそのメソッドはprivateになります。 つまり、そのメソッドはそのクラス内でしか呼び出せなくなります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class CoffeeShop
    privateVal = "Cappuccino"
    privateFun = -> console.log "Yummy"
    publicVal: privateVal
    publicFun: -> privateFun()

coffeeshop = new CoffeeShop()
console.log coffeeshop.privateVal           # エラー
console.log coffeeshop.publicVal            # Cappuccino
coffeeshop.privateFun()                     # エラー
coffeeshop.publicFun()                      # Yummy

メソッド名の先頭に @ をつけると、そのメソッドはクラスメソッド(staticメソッド)になります。 つまり、そのメソッドはインスタンスを作成せずに直接使用できるようになります。

1
2
3
4
5
6
7
8
9
class CoffeeShop
    @staticVal: "Caffè mocha"
    @staticFun: -> console.log "Yummy"

coffeeshop = new CoffeeShop()
console.log coffeeshop.staticVal           # エラー
console.log CoffeeShop.staticVal           # Caffè mocha
coffeeshop.staticFun()                     # エラー
CoffeeShop.staticFun()                     # Yummy

あとがき

CoffeeScriptを使っていて感じるのは、CoffeeScriptは新しい言語と言うより、JavaScriptの良い機能だけを集めたツールという感覚です。 CoffeeScriptからコンパイルされるJavaScriptは、単に元のソースコードの言葉を置き換えているだけではなく、 自力で書いたJavaScriptよりも美しく変換されていると感じます。 CoffeeScriptからコンパイルされるJavaScriptを見ることで、JavaScript自体への理解も深まるかと思います。

2月末のOUCC春合宿では、そんなCoffeeScriptを使ってWebアプリ Giraf (http://giraf.harusamex.com) を作りました。 Girafは、ローカルにある動画からGifアニメを作ることができます。ぜひ使ってみてください。