はじめてのCoffeeScript
今日は、CoffeeScriptを見ていこうと思います。
公式のドキュメントは、ここhttp://coffeescript.org/にあります。
簡単にまとめると、
・functionは-> ・クラスをclass文で書ける ・ifやforは後置できる ・引数の()は省略できる ・関数で最後に評価した値を自動的に返す ・インデントで構造を表す ・リスト内包表記が書ける ・比較で1 < x < 5の書き方ができる ・"#{a} is variable"のように、文字列に変数を埋め込める ・文字列、正規表現を複数行で書ける ・switchはRubyのcaseにそっくり ・例外はほぼjsと一緒
で、演算子が一部変更されてます
js -> coffee === -> is !== -> isnt ! -> not && -> and || -> or true -> true, yes, on false -> false, no, off this -> @, this in -> of なし -> in
こんな感じ?
RubyとPythonに慣れてれば、すごくしっくり来そうですね。
$ coffee -c ファイル名
で出来ます。同じ名前のjsファイル吐きます。-cをつけずに、
$ coffee ファイル名
だと、jsファイルを吐かずに実行してくれます。
CoffeeScriptをコンパイルして得られるjsは、中身を見ればわかると思いますが、グローバル空間を汚さないようになっています。
なので、下のコードは、jsの方はブラウザのコンソールにコピペすれば関数を呼べるように書いていますが、CoffeeScriptの方はコンパイル後のjsをそのままコピペしても関数は呼べません。動かす際はコンパイル後のjsの無名関数の中で関数を呼び出してください。
それでは本編に入ります。
普通に文法を見てもおもしろくないので、jsと比較しつつ、遊んでみましょう。
まず、FizzBuzzを比べてみます。ifとforを使いつつ、関数にしてみます。
javascript
function fizzbuzz( n ) { for ( var i = 1; i <= n; i++ ) { // FizzかBuzzがついたら表示する文字列 var message = ''; // 3の倍数ならFizzをつける if ( i % 3 === 0 ) { message += 'Fizz'; } // 5の倍数ならBuzzをつける if ( i % 5 === 0 ) { message += 'Buzz'; } // messageが空なら数字を表示する console.log( message || i ); } }
CoffeeScript
fizzbuzz = (n) -> for i in [1..n] # FizzかBuzzがついたら表示する文字列 message = '' # 3の倍数ならFizz, 5の倍数ならBuzzをつける message += 'Fizz' if i % 3 is 0 message += 'Buzz' if i % 5 is 0 # messageが空なら数字を表示する console.log message or i
coffeeの方がかなり簡潔で見やすいです。
ifが後置で書けるので、かなりすっきりしてます。
1からnまでの配列をRubyのRangeみたいに[1..n]と書けるのがいいですね。
jsでは0がfalseなので、coffeeでunlessを使ってみましょう。
CoffeeScript
fizzbuzz = (n) -> for i in [1..n] # FizzかBuzzがついたら表示する文字列 message = '' # 3の倍数ならFizz, 5の倍数ならBuzzをつける message += 'Fizz' unless i % 3 message += 'Buzz' unless i % 5 # messageが空なら数字を表示する console.log message or i
やっぱり、unlessはすっきりします。
さらに、forを後置して、こんな風にも書けます。
関数にしなければ、ワンライナーですね。
CoffeeScript
fizzbuzz = (n) -> console.log [['Fizz'][i%3], ['Buzz'][i%5]].join("") or i for i in [1..n]
FizzBuzzはこんなもんにしておきましょう。
CoffeeScriptは書いてて楽しいです。
次に、クラス定義の違いを見てみましょう。
Carクラスを書いてみます。
車の名前を属性にして、走るメソッドを入れてみます。
javascript
// Carオブジェクトのコンストラクタ function Car( name ) { this.name = name; } // 走るメソッド Car.prototype.run = function( speed ) { console.log( this.name + 'が' + speed + 'キロで走ってます。' ); }
Coffeescript
// Carクラス class Car constructor: (@name) -> # 走るメソッド run: (speed) -> console.log "#{@name}が#{speed}キロで走ってます。"
CoffeeScriptはこれでprototypeに入れてくれるので、かなり楽ですね。
クラスベースのオブジェクト指向言語に慣れた人は、coffeeの方がかなり見やすいと思います。
最後に、じゃんけんをするプログラムを書いて、比べてみましょう。
jsとcoffeeでswitchの扱いやすさの差が歴然です。
もはやswitchじゃなくてcaseと書きたいレベル。
javascript
function janken() { // 1がグー、2がチョキ、3がパー var hands = ['ぐー', 'ちょき', 'ぱー']; // プレイヤーの手 var playerHand = window.prompt("じゃんけんをしましょう!\n何を出しますか?\n1. ぐー 2. ちょき 3. ぱー"); // 日本語入力に対応 // 不正な入力があったらはじく if ( ['1', '2', '3'].indexOf( playerHand ) === -1 ) { switch( playerHand ) { case 'ぐー': case 'グー': playerHand = 1; break; case 'ちょき': case 'チョキ': playerHand = 2; break; case 'ぱー': case 'パー': playerHand = 3; break; default: alert('何言ってるかわかんないです。'); return; } } // 内部処理用に、playerHandの値をhandsのインデックスに合わせる playerHand -= 1; var playerHandStr = hands[ playerHand ]; // COMの手。ランダムで決める var comHand = Math.floor( Math.random() * 3 ); var comHandStr = hands[ comHand ]; // 勝敗表示用の文字列 var bothHandsStr = 'あなた: ' + playerHandStr + "\n" + 'COM : ' + comHandStr + "\n"; var win = "あなたの勝ち!"; var lose = "あなたの負け…"; var draw = "あいこ!"; // 勝敗判定 // アルゴリズム使用([http://staku.designbits.jp/check-janken/]) // resultが0であいこ、1でCOMの勝ち、2でplayerの勝ち var result = ( playerHand - comHand + 3 ) % 3; var messages = [ draw, lose, win ]; // 結果を表示 alert( bothHandsStr + messages[ result ] ); }
CoffeeScript
janken = -> # 1がグー、2がチョキ、3がパー hands = ['ぐー', 'ちょき', 'ぱー'] # プレイヤーの手 playerHand = window.prompt "じゃんけんをしましょう!\n何を出しますか?\n1. ぐー 2. ちょき 3. ぱー" # 日本語入力に対応 # 不正な入力があったらはじく unless playerHand in ['1', '2', '3'] switch playerHand when 'ぐー', 'グー' then playerHand = 1 when 'ちょき', 'チョキ' then playerHand = 2 when 'ぱー', 'パー' then playerHand = 3 else alert '何言ってるかわかんないです。' return # 内部処理用にplayerHandの値をhandsのインデックスに合わせる playerHand -= 1 playerHandStr = hands[playerHand] # COMの手 comHand = Math.floor(Math.random() * 3) comHandStr = hands[comHand] # 勝敗表示用の文字列 bothHandsStr = "あなた: #{playerHandStr}\nCOM : #{comHandStr}\n" win = "あなたの勝ち!" lose = "あなたの負け…" draw = "あいこ!" # 勝敗判定 # アルゴリズム使用([http://staku.designbits.jp/check-janken/]) # resultが0であいこ、1でCOMの勝ち、2でplayerの勝ち result = (playerHand - comHand + 3) % 3 messages = [draw, lose, win] # 結果を表示 alert bothHandsStr + messages[result]
いかがですか?個人的にはcoffeeの方がかなり書きやすかったです。
CoffeeScriptの文法をさらっとなめてみました。DOMにも触ろうと思ったのですが、すでに相当な文量になってしまっているので、やめます。
CoffeeScriptを使えば、クライアントサイドのコーディングがかなり楽になりそうですね。