CoffeeScript の最初の一杯: 第 1 回 入門
はじめに
CoffeeScript は、JavaScript をベースに作成されたプログラミング言語です。CoffeeScript は有効な JavaScript にコンパイルされるので、Web ブラウザーで実行することも、Node.js などのサーバー・アプリケーション用の技術で使用することもできます。JavaScript へのコンパイルは、通常はすんなり行われます。それによって生成される JavaScript は、多くのベスト・プラクティスと一致しています。この記事を読んで、CoffeeScript プログラミング言語の機能について学んでください。記事では CoffeeScript をインストールしてコンパイラーを実行した後、Web ページで CoffeeScript を使用する単純なサンプル・アプリケーションを検証します。
この記事で使用するソース・コードはここからダウンロードしてください。
CoffeeScript の魅力
最近では、JavaScript が最も重要なプログラミング言語であることに議論の余地はありません。JavaScript はブラウザーの言語ですが、デスクトップ・アプリケーションやモバイル・アプリケーションでも頻繁に使用されるようになってきました。Node.js の人気が高まるなか、JavaScript はサーバー・アプリケーションやシステム・アプリケーションを構築する際の有効な選択肢となっています。一部の開発者は、その一貫性のない構文と奇抜な実装を主な理由として JavaScript に強く抵抗していますが、JavaScript 仮想マシンが以前に比べて標準化されてきたことから、奇抜な実装はなくなりつつあります。一貫性のない構文に関しては、JavaScript の次なる進化である、ECMAScript.next (CoffeeScript の影響を強く受けた新しい標準) によってある程度対処されることが見込まれます。けれども、新しい標準が合意されて主流の仮想マシンで実装されるようになるまでは、JavaScriptの構文には改善の余地が大いに残されています。
JavaScript ランタイムのコードを作成する場合、CoffeeScript は魅力的な選択肢となります。構文という点では、JavaScript はかなり混乱しています。JavaScript には、関数型のプログラミング言語の機能が数多く用意されており、特に Scheme の影響を強く受けています。JavaScript には Scheme のさまざまな概念が継承されていますが、構文に関してはその限りでありません。Scheme の構文は S 式をベースとした非常に単純なものですが、JavaScript が使用するのは C 言語に似た構文です。そのため、JavaScript には関数型の概念がありながら、その冗長な構文にはそれらの概念を表現するのにふさわしい構成体がありません。例えば、JavaScript では高階関数 (入力パラメーターに他の関数を含めることができる関数) を使用することができます。これは多くの言語にはない有用で強力な特徴ですが、リスト 1 に示すとおり、JavaScript の構文で高階関数を表現するとなると、簡潔に表現することはできません。
リスト 1. 簡潔ではない JavaScript
pmb.requestPaymentInfo('type', function(info){ $('result').innerHTML = info.name; });
上記の例には、括弧、コンマ、波括弧、セミコロン、言語のキーワードなど、本当に必要とは言えない定型表現が溢れています。
JavaScript は主に、クライアント・サイドの Web アプリケーション言語として使用されています。Cocoa、Windows Forms、Android などのデスクトップおよびモバイル・アプリケーション・フレームワークは、いずれもオブジェクト指向です。オブジェクト指向のパラダイムは万能ではないものの、グラフィカル・ユーザー・インターフェースを使用するアプリケーションとの相性はぴったりです。JavaScript も同じくオブジェクト指向の言語であり、継承を備えていますが、JavaScript はプロトタイプ・ベースの言語です。つまり、ほとんどのアプリケーション・フレームワークが使用しているようなクラス・ベースの言語ではありません。そのため、JavaScript でアプリケーションをプログラミングするのは非常に厄介になることがあります。
JavaScript のこれらの欠点に対処したのが、CoffeeScript です。CoffeeScript には以下の特徴があります。
- 括弧やコンマなどの定型表現の少ない単純化された構文を使用します。
- ホワイトスペースをコード・ブロックの編成手段として使用します。
- 関数を単純な構文で表現できるようになっています。
- クラス・ベースの継承に対応します (これはオプションですが、アプリケーションを開発する際には非常に役立つはずです)。
抽象化された構文を使用する CoffeeScript には、JavaScript にはない何らかの欠点があるのではないかと推測する方もいるでしょう。例えば、CoffeeScript は JavaScript を実行する場合に比べ、はるかに実行時間がかかるのではないか、あるいは重いランタイム・ライブラリーが必要になるのではないか、などと思うかもしれませんが、実は CoffeeScript は、簡潔かつ効率的な JavaScript にコンパイルされます。コンパイルされた内容そのものを常に目で確認できるため、余計なものが何も取り込まれていないことに確信を持つことができます。しかも、CoffeeScript は完全に機能する JavaScript にコンパイルされるので、いかなるタイプのランタイム・ライブラリーも必要ありません。さらに CoffeeScript の構文は、最小限のランタイム・オーバーヘッドで JavaScript の能力を最大限に活用することができます。
前提条件
前述のとおり、CoffeeScript は、Node.js をベースに実行されるサーバー・アプリケーションやシステム・アプリケーションを作成するために使用することができます。ただし、CoffeeScript と Node.js との関係はそれだけではありません。CoffeeScript をインストールするには、最初に Node.js をインストールする必要があります。その理由は、以下のとおりです。
- CoffeeScript は、NPM (Node Package Manager) を使用して Node.js パッケージとして配布されます。
- CoffeeScript はコンパイルする必要があります。CoffeeScript のコンパイラーは実際には CoffeeScript で記述されているため、JavaScript ランタイムがなければ CoffeeScript をコンパイルすることはできません。CoffeeScript のコンパイルに最適なのが、Node.js の中核をなす V8 JavaScript 仮想マシンです。
したがって、この記事の例に従うには、Node.js をインストールする必要があります。
インストール
JavaScript をコマンド・ラインから実行できたらよいのにと思ったことはありませんか?私は今までそう思ったことはありませんが、CoffeeScript によってそう思うようになるかもしれません。Node.js では、JavaScript をコマンド・ラインから実行することも、実行可能スクリプトの一部として実行することもできます。Node.js のこの重要な機能は、(CoffeeScriptで記述された) CoffeeScript コンパイラーに必要なランタイムを提供し、CoffeeScript コードをコマンド・ラインで実行できるようにします。
まず始めに必要な作業は、Node.js
をインストールすることです。インストールするにはいくつかの方法があります。ソース・コードをコンパイルするという方法、あるいはさまざまなシステム用に用意されたインストーラーのいずれかを実行するという方法を使用することができます。いずれにしても、Node.js
がインストールされて、パスに設定されていることを確認するには、コマンド・ラインから node -v
を実行します。
Node.js をインストールすると、おまけが付いてきます。それは、NPM (Node Package Manager) です。コマンド・ラインから npm -v
を実行し、NPM がインストールされてパスに設定されていることを確認したら、この NPM を使用して CoffeeScript をインストールすることができます。その手順は、以下のとおりです。
- コマンド・ラインから
npm install --global coffee-script
を実行します。--global
フラグによって、特定のプロジェクトからのみでなく、システム全体で CoffeeScript を使用できるようになります。 npm
コマンドを実行すると、「/usr/bin/coffee -> /usr/lib/node_modules/coffee-script/bin/coffee」のような出力が表示されます。これにより、NPM が /usr/bin 内にショートカットを作成し、coffee 実行ファイルが適切なパスに配置されます。このプログラムが、CoffeeScript のコンパイラー兼インタープリターです。
- 実行ファイルがパスに設定されていることを確認するには、コマンド・ラインから
coffee -v
を実行します。
CoffeeScript 環境が適切にセットアップされていることを確実にするためには、最後にもう 1 つのステップを行う必要があります。それは、開始するすべての Node.js プロセスで CoffeeScript を使用できるようにするために、Node.js の NODE_PATH に CoffeeScript を追加することです。Node.js は認識しない関数を検出すると、NODE_PATH でモジュール (ライブラリー) を検索します。
この記事の例では、主に CoffeeScript 実行ファイルのランタイムとして Node.js を使用します。そのためには、単純にすべての NPM モジュールを
NODE_PATH に追加しておくのが最も簡単な方法です。NPM モジュールが配置されている場所を見つけるには、npm ls
-g
を実行します。これによって見つかった場所を環境変数 NODE_PATH が指すようにしてください。例えば、npm ls
-g
の出力結果が /usr/lib だとすると、NPM モジュールは /usr/lib/node_modules に配置されていることになります。この場合、export NODE_PATH=/usr/lib/node_modules を実行して、NODE_PATH 環境関数を設定します。
さらに効率化を図るには、前述のコマンドを起動スクリプト (例えば、~/.bash_profile) に組み込むという方法もあります。変更内容を確認するには、Node
を実行して Node.js シェルを起動してから、require('coffee-script')
を実行します。これにより Node.js シェルが CoffeeScript ライブラリーをロードするはずです。ロードが正常に完了すれば、CoffeeScript 環境の準備は完了です。これで、CoffeeScript の調査を開始することができます。まずは、コンパイラーから見てみましょう。
コンパイラー
CoffeeScript コンパイラーを実行するのは簡単で、coffee -c
と入力するだけです。これによって、CoffeeScript の REPL (Read-Evaluate-Print-Loop) が起動されます。コンパイラーを実行する際には、コンパイラーにコンパイル対象の CoffeeScript ファイルを渡さなければなりません。そこで、cup0.coffee という名前のファイルを作成し、そのファイルにリスト 2 の内容を貼り付けます。
リスト 2. Cup 0
for i in [0..5] console.log "Hello #{i}"
リスト 2 に示された 2 行のコードがどんなことを行うかは、おそらくお察しのことでしょう。coffee cup0.coffee を実行すると、リスト 3 の出力が表示されます。
リスト 3. 最初の CoffeeScript の実行
$ coffee cup0.coffee Hello 0 Hello 1 Hello 2 Hello 3 Hello 4 Hello 5
何が行われているのかをより良く理解するには、コンパイラーを実行してみてください。coffee -c cup0.coffee
と入力すると、cup0.js という名前のファイルが作成されます。cup0.js の内容は、リスト 4 のとおりです。
リスト 4. Cup 0 の JavaScript
(function() { var i; for (i = 0; i <= 5; i++) { console.log("Hello " + i); } }).call(this);
CoffeeScript を使用するメリットは、CoffeeScript の構文は JavaScript より簡潔でありながらも、非常に単純で論理的な JavaScript にコンパイルされることです。このコードのすべてが関数の中にラップされていることに疑問を感じるかもしれませんが、その理由は、JavaScript では関数レベルのスコープしかサポートされないためです。すべてのコードを関数の中にラップすることで、変数のスコープがその関数のみとなり、グローバル変数にならないこと (あるいは既存のグローバル変数が変更されないこと) が確実になります。
cup1.coffee という名前の新しいファイルを開いて、今度はもう少し複雑なリスト 5 のコードを入力してください。
リスト 5. Cup 1
stdin = process.openStdin() stdin.setEncoding 'utf8' stdin.on 'data', (input) -> name = input.trim() process.exit() if name == 'exit' console.log "Hello #{name}" console.log "Enter another name or 'exit' to exit" console.log 'Enter your name'
リスト 5
のプログラムは、ユーザーに対してユーザー名を入力するように促し、入力されたユーザー名に対する挨拶のメッセージを出力します。標準入力からの入力を読み取るための組み込みライブラリーは、JavaScript
にはありませんが、Node.js にはあります。リスト 5 の例では CoffeeScript と Node.js を共存させることで、Node.js
のライブラリーを利用しています。C
などの言語では、標準入力からの読み取りはブロッキング呼び出しであり、標準入力からの読み取りが完了するまで他のコードを実行することができません。Node.js に馴染みがあれば、ご存知のとおり、このような操作は不可能です。つまり、Node.js ではブロッキング I/O は許可されないため、stdin.on
にコールバックを登録する必要があります。
coffee -c cup1.coffee
を実行して、CoffeeScript コンパイラーが生成する JavaScript を確認してください (リスト 6 を参照)。
リスト 6. Cup 1 の JavaScript
(function() { var stdin; stdin = process.openStdin(); stdin.setEncoding('utf8'); stdin.on('data', function(input) { var name; name = input.trim(); if (name === 'exit') { process.exit(); } console.log("Hello " + name); return console.log("Enter another name or 'exit' to exit"); }); console.log('Enter your name'); }).call(this);
stdin.on
関数は、典型的なイベント・バインディング・フォーマットを使用します。つまり、リッスンする対象のイベントの種類 ('data'
) を指定し、さらにそのイベントが起動されたときに実行されるコールバック関数を提供します。コンパイルされた JavaScript には、インライン関数を作成して、その関数を別の関数に渡す、よくある冗長な JavaScript を見て取れます。この JavaScript を、対応する CoffeeScript と見比べてください。括弧や波括弧、そしてセミコロンやキーワードなど、いつもの定型表現が懐かしく感じられませんか?
CoffeeScript プログラムをコンパイルする方法がわかったところで、次のセクションでは CoffeeScript を知るのに最も役立つ機能の 1 つ、REPL に注目します。
REPL
REPL は、多くのプログラミング言語で使用されている標準ツールで、とりわけ関数型のプログラミング言語でよく使用されています。REPL は Ruby の IRB
に相当します。CoffeeScript の REPL は「coffee
」と入力するだけで起動されます。一例として、この CoffeeScript の機能を使って単純な問題を解決してみます (リスト 7 を参照)。
リスト 7. REPL を使用する
coffee> nums = [1..10] [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] coffee> isOdd = (n) -> n % 2 == 1 [Function] coffee> odds = nums.filter isOdd [ 1, 3, 5, 7, 9 ] coffee> odds.reduce (a,b) -> a + b 25
REPL に式を入力するたびに、REPL はその式を評価して結果を出力し、それからまた、次の式を待機します。上記の例では、1 から 10 までの範囲で nums
という変数を定義しています。すると REPL
はすぐさま、定義された変数の値を出力します。この機能が直接役に立つのは、例えば定義した範囲が inclusive (最後の数値 (上記の例では 10)
が範囲に含まれること) であるか、exclusive (最後の数値が範囲に含まれないこと) であるかを忘れてしまった場合です。REPL の出力には 10 が含まれているので、定義した範囲は inclusive であることがわかります。exclusive の範囲が必要だったとしたら、nums = [1...10]
と定義することになります。
上記のリストで次に定義されているのは、isOdd
関数です。CoffeeScript
には関数型を宣言するための極めて簡潔な構文があります。この構文は、JavaScript の関数型の特性を踏まえた便利な機能です。上記の例では、REPL は isOdd
変数が関数と同等であることを示すために、[Function]
と表示しているだけに過ぎません。続いて、odds
という新しい変数が宣言されています。odds
の値を取得するには、nums
でフィルター関数を呼び出して isOdd
に渡します。これによって、isOdd
に渡されると true
になる要素で構成された配列が新たに生成されます。次に、odds
で reduce
関数を呼び出します。関数を渡すごとに、配列に含まれるそれぞれの値が前の合計に加算されていき、最終的に配列のすべての値が合計されて、REPL がその合計値 25 を表示します。
次のセクションでは、あらゆるJavaScript 開発者に身近なトピックとして、ブラウザーでのスクリプティングを取り上げます。
単純なサンプル Web アプリケーション
これまでのところで、CoffeeScript ファイルを作成して JavaScript にコンパイルする方法を学びました。その方法はもちろん Web アプリケーションで実際に使用することができますが、開発のためには、それよりも簡単な方法があります。CoffeeScript コンパイラーはブラウザー内部で実行できることから、CoffeeScript を Web ページで直接使用することができますが、ハイパフォーマンスの Web アプリケーションを構築する場合には、このように CoffeeScript を使用することは推奨されません。CoffeeScript コンパイラーはラージ・ファイルであるため、CoffeeScript をオン・ザ・フライでコンパイルするとなると、確実に動作が遅くなるからです。それよりも、CoffeeScript には明らかな「本番環境への道」が開けたアプリケーションを開発する簡単な方法があります。
CoffeeScript は JavaScript のツールキットでもフレームワークでもありません。CoffeeScript は、プログラミング言語です。したがって、DOM 関連のコンビニエンス関数はそれほど多く組み込まれていません。しかし、CoffeeScript をお気に入りのツールキットで使用することはできます。最も一般的なのは、CoffeeScript と jQuery の組み合わせです。リスト 8 に、CoffeeScript と jQuery を使用する単純な Web ページを示します。
リスト 8. Web ページ内で使用される CoffeeScript
<html> <head> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"> </script> <script src="//jashkenas.github.com/coffee-script/extras/coffee-script.js"> </script> <script type="text/coffeescript"> gcd = (a,b) -> if (b==0) then a else gcd(b, a % b) $("#button").click -> a = $("#a").val() b = $("#b").val() $("#c").html gcd(a,b) </script> </head> <body> A: <input type="text" id="a"/><br/> B: <input type="text" id="b"/><br/> <input type="button" value="Calculate GCD" id="button"/> <br/> C: <span id="c"/> </body> </html>
この Web ページは、Google Ajax ライブラリーを使用して jQuery をロードします。CoffeeScript
コンパイラー・ライブラリーは、CoffeeScript の作成者である Jeremy Ashkenas の Github リポジトリー (「参考文献」を参照)
からロードしています。続いてこのコードに組み込まれているのは、スクリプト・ブロックです。このスクリプト・ブロックのタイプは text/javascript
ではなく、text/coffeescript
となっているため、CoffeeScript コンパイラーはスクリプトの内容をコンパイルしなければならないことを認識します。このスクリプトは、2
つの整数の最大公約数を計算する gcd
という関数を作成します。次に jQuery
を使用して、ページ上のボタンを対象としたクリック・ハンドラーを作成します。このハンドラー内で、2 つのテキスト入力の値を取って gcd
関数に渡します。そして、この関数による評価結果が Web ページに書き込まれるという仕組みです。$()
、val()
、html()
などは jQuery 関数ですが、これらの関数は CoffeeScript でも簡単に使用できるため、CoffeeScript の簡潔な構文を利用することができます。
まとめ
今回の記事では、CoffeeScript について簡単に紹介しました。記事の手順に従って開発環境をセットアップすれば、今すぐ REPL を使用して CoffeeScript について詳しく調べることができます。コンパイラーを使用して、どのような JavaScript が生成されるかを調べる方法も、CoffeeScript を作成して Web ページで直接実行する方法も、この記事を読んで習得できているはずです。また、詳しくは説明しませんでしたが、サンプル・コードで多少 CoffeeScript の構文を味わえたことと思います。
連載の第 2 回では CoffeeScript の主要な概念について、その詳細を探ります。
ダウンロード可能なリソース
- このコンテンツのPDF
- Article source code (cs1.zip | 1KB)
関連トピック
- 「Node.js とは一体何か?」(developerWorks、2011年5月) では、なぜ Node がサーバーの動作に関する概念を変えるサーバー・サイドの JavaScript インタープリターとなるかを説明しています。
- Node.js: このアプリケーションについて詳しく学ぶには、ここが出発点となります。
- 「Node.js をクラウド環境での開発用のフルスタックとして使用する」(developerWorks、2011年4月) で、Node.js をクラウド技術と組み合わせる方法を詳しく説明しています。
- 「Google Web Toolkit と Eclipse Galileo を使ったハイパフォーマンスの Web 開発」(developerWorks、2009年10月): JavaScript にコンパイルするという考えは、新しいものではありません。これは、Java プログラミング言語のファンにとって必読の記事です。
- 「出発進行! Rails 3 の紹介」(developerWorks、2010年3月) を読むと、CoffeeScript が Ruby on Rails にどのように組み込まれているかがわかります。この記事で、Rails に追加されたその他の新機能を調べてください。
- Github での CoffeeScript の説明: CoffeeScript について学ぶには、ここが出発点となります。
- 「モバイル Web 用の Ajax アプリケーションを作成する」(developerWorks、2010年3月) で、Ajax をモバイル Web アプリケーションで使用する方法について詳しく説明しています。
- Twitter での developerWorks: 今すぐ登録して developerWorks のツイートをフォローしてください。
- Node.js: Node.js をダウンロードしてください。スケーラブルなネットワーク・プログラムを容易に構築できるようになります。
- IBM 製品の評価版: DB2、Lotus、Rational、Tivoli、および WebSphere のアプリケーション開発ツールとミドルウェア製品を体験するには、評価版をダウンロードするか、IBM SOA Sandbox のオンライン試用版を試してみてください。