はじめに
function、{}、;、return——JavaScriptを書いていると、ロジックそのものよりも記号の数の方が多いと感じる瞬間はないでしょうか。CoffeeScriptは、まさにそのノイズを削ぎ落とすために2009年に生まれた言語です。「Unfancy JavaScript(気取らないJavaScript)」を掲げ、インデントで構造を表し、余計な記号を書かずに済むJavaScriptへとコンパイルします。
2026年の今、TypeScriptが主流になった中でCoffeeScriptを選ぶ理由はあるのか——結論から言うと、型チェックが目的ならTypeScriptの方が適していますが、CoffeeScriptには「短く書く」ことに特化した独自の価値が今も残っています。実際、アロー関数や分割代入、クラス構文といった今のJavaScriptの書き味には、CoffeeScriptが切り開いた道の影響が色濃く残っています。
まずは実際にどれくらい短く書けるのか、手を動かして確かめてみましょう。
CoffeeScriptとは
CoffeeScriptは、JavaScriptに変換(コンパイル)される言語です。Pythonのようにインデントでブロックを表現し、varや;、多くの場面で{}も書かずに済みます。現在の最新版はv2系で、出力されるJavaScriptもES2015以降の構文(クラス、アロー関数、async/awaitなど)に対応しています。
主な特徴
- 記号が少ない - 中括弧・セミコロンが不要で、インデントがそのままブロック構造になる
- 式指向の文法 -
ifや関数もほとんどが値を返す式として扱え、最後の式が暗黙的に返り値になる - 豊富な糖衣構文 - 文字列内挿(
#{})、内包表記、存在演算子(?)、束縛メソッド(=>)などが標準で使える - 現代的なJS出力 - CoffeeScript 2はクラスや
async/await、JSXまで含めたES2015+のコードを生成する
インストール
CLIとして使う場合はグローバルインストールします。
npm install --global coffeescript
プロジェクトの一部として使う場合はローカルに追加します。
npm install --save-dev coffeescript
インストール後はcoffeeコマンドでコンパイルや実行ができます。
coffee --compile app.coffee # app.js を生成
coffee app.coffee # そのまま実行
coffee --watch --compile src/ # 変更監視しながらコンパイル
CoffeeScriptのサンプルを動かす
CoffeeScriptでは、関数定義に->、文字列内挿に#{}を使い、ifを後置で書けます。次のコードは、名前を受け取って挨拶文を組み立てる関数です。returnを書いているのは早期リターンの行だけで、最後の式は自動的に返り値になります。
greet = (name) ->
return "こんにちは、ゲストさん!" if name.length is 0
"こんにちは、#{name}さん!お名前は#{name.length}文字ですね。"
console.log greet('太郎')
console.log greet('')
実際に動かせるものが下です。入力欄に文字を打つと、その場で挨拶文が変わります。入力を空にすると、if name.length is 0の分岐に切り替わることが確認できます。
functionも{}もreturn(早期リターン以外)も書いていない点に注目してください。CoffeeScriptではgreet関数の本体がそのまま「最後に評価した式」を返すため、JavaScriptで書くよりも行数が短くなります。if ... is 0の部分をif name.length > 10に変えれば、10文字を超えたときだけ挙動を変える、といった条件分岐もすぐに試せます。
基本的な使い方
CoffeeScriptの基本文法を、JavaScriptとの対比で見てみましょう。変数宣言にvar/letは不要で、文字列内挿は#{}を使います。
name = "CoffeeScript"
version = 2
# 文字列内挿
message = "#{name} v#{version} で書いています"
# 条件式(値を返す)
status = if version >= 2 then "モダン" else "レガシー"
# 配列とループ
langs = ["JS", "TS", "CoffeeScript"]
for lang in langs
console.log "#{lang} が好きです"
# クラス
class Animal
constructor: (@name) ->
speak: -> "#{@name}が鳴きました"
cat = new Animal("たま")
console.log cat.speak()
constructor: (@name) ->のように引数名の前に@を付けるだけで、this.name = nameへの代入を省略できます。CoffeeScriptは「よく書くパターンを短く書けるようにする」ことに文法の多くを割いている言語だと分かります。
実践的なユースケース
クラスの束縛メソッドでイベントを扱う
JavaScriptでクラスのメソッドをイベントハンドラに渡すと、thisがずれてbind(this)が必要になることがよくあります。CoffeeScriptは->の代わりに=>でメソッドを定義するだけで、インスタンスに束縛されたメソッドを作れます。ボタンを押すたびにカウントが増える、次のサンプルで確認してください。
class Counter
constructor: (@el) -> @count = 0
increment: =>
@count += 1
@el.textContent = @count
counter = new Counter(countEl)
button.addEventListener 'click', counter.increment
increment: =>が=>(ファットアロー)で定義されているため、counter.incrementをaddEventListenerにそのまま渡しても、内部の@count(this.count)は常にcounterインスタンスを指し続けます。->(シンアロー)に書き換えて動かすと、thisがずれてカウントアップに失敗する様子も確認できます。document.getElementById('btn')?の?は存在演算子で、要素が見つからない場合にaddEventListenerの呼び出し自体をスキップする安全策です。
リスト内包表記でデータを絞り込む
CoffeeScriptには.filter().map()の代わりに使えるリスト内包表記があります。for ... when ...の形で、条件に合う要素だけを変換しながら1行で取り出せます。上限価格を入力すると、その場で商品リストが絞り込まれる例を見てみましょう。
products = [
{ name: 'マウス', price: 2500 }
{ name: 'モニター', price: 32000 }
]
cheap = ("#{p.name}: #{p.price}円" for p in products when p.price <= 10000)
console.log cheap # => ['マウス: 2500円']
for p in products when p.price <= maxという1行が、JavaScriptのproducts.filter(p => p.price <= max).map(p => ...)に相当します。上限価格を5000のように小さくすると絞り込みが強まり、200000まで上げると全件表示に戻ることが確認できます。
ブラウザ上でCoffeeScriptをJavaScriptに変換する
CoffeeScriptのコンパイラ自体もJavaScriptパッケージとして配布されているため、CoffeeScript.compile()をブラウザから直接呼び出せます。エディタツールやPlaygroundを自作するときに使えるパターンです。左のテキストエリアにCoffeeScriptコードを書くと、右側にコンパイル結果のJavaScriptがリアルタイムで表示されます。
import CoffeeScript from 'coffeescript@2.7.0'
const source = 'square = (x) -> x * x\nconsole.log square 5'
const js = CoffeeScript.compile(source, { bare: true })
console.log(js)
compile()の第2引数に渡している{ bare: true }は、出力全体を関数でラップしない(トップレベルの(function() {...})()を付けない)オプションです。テキストエリアの中身をわざと崩して(例えば->を消して)みると、try/catchで捕まえたコンパイルエラーがそのまま表示されるので、CoffeeScriptの構文チェックがどこで働いているかも体感できます。
まとめ
CoffeeScriptは、インデントベースの文法・文字列内挿・存在演算子・束縛メソッド・リスト内包表記といった仕組みで、JavaScriptを短く書くことに徹底的にこだわった言語です。今のJavaScript/TypeScriptが手に入れたアロー関数やクラス構文の書き味は、こうした先行言語が示した方向性の延長線上にあります。
型による安全性を最優先するならTypeScriptが妥当な選択ですが、「とにかく記述量を減らしたい」「Pythonライクな読みやすさが欲しい」というときには、CoffeeScriptの文法は今も検討する価値があります。まずはnpm install --global coffeescriptで手元に入れて、.coffeeファイルをcoffee --compileしてみるところから始めてみてください。