訳注サンプルコードなどは本家のリファレンスのものを引用しつつ、勝手&適当に翻訳しています。間違いなどあればコメント欄などでご指摘下さい。 CoffeeScriptのバージョンが1.0.1の時のものです。 基本行末のセミコロン ; は不要。ただし1行に複数の式を書くときは ; で区切る。関数に引数を渡す括弧 (...) は不要。 print "coffee" のように関数を呼べる。ただし引数が無い場合は空の括弧 ( ) が必要。関数やif文、switch文、try/catch文などでブロックを中括弧 {...} で囲む代わりに、Pythonのようにインデントを揃えることでブロックを表現する。なのでインデントは超重要。代入変数宣言の var は不要。 「 = 」で代入する。(バージョン0.9より前は : だった)number = 42 opposite = true 条件分岐(if, else など)後置のifが使える。 number = -42 if opposite if文の括弧 ( ) や中括弧 { } は不要。演算子に「and」や「or」を使える。 if happy and knowsIt clapsHands() chaChaCha() else showIt() 1行で if/else も書ける。この場合のif文は値を返す。 date = if friday then sue else jill options || (options = defaults) の省略記法options or= defaults 値の有無 (null, undefined以外なら真) alert "I knew it!" if elvis? 演算子(and, or, not など)
演算子のエイリアス
launch() if ignition is on volume = 10 if band isnt SpinalTap
繰り返し(while, until)後置のwhileとuntilが使える。 # Econ 101(経済学の一番初歩の講座) if this.studyingEconomics buy() while supply > demand sell() until supply > demand while, until文は値(配列)を返す。 # Nursery Rhyme(子守唄) num = 6 lyrics = while num -= 1 num + " little monkeys, jumping on the bed. One fell out and bumped his head." 関数(function)(引数) -> 式 という形で書く。 return は不要。 引数がないときは () も省略可能。square = (x) -> x * x cube = (x) -> square(x) * x 引数はデフォルト値を持てる。 fill = (container, liquid = "coffee") -> "Filling the #{container} with #{liquid}..." 配列とオブジェクト普通のJavaScriptと同じように書ける。 song = ["do", "re", "mi", "fa", "so"] singers = {Jagger: "Rock", Elvis: "Roll"} 「 , 」の代わりに改行でも良い。matrix = [ 1, 0, 1 0, 0, 1 1, 1, 0 ] オブジェクトはYAMLのように書ける。 kids = brother: name: "Max" age: 11 sister: name: "Ida" age: 9 math = root: Math.sqrt square: square cube: (x) -> x * square x クォートで囲まなくてもオブジェクトのプロパティ名に「class」を使える。 $('.account').attr class: 'active' スコープスコープはRubyと同じ。var は不要。 outer = 1 changeNumbers = -> inner = -1 # inner は関数内で宣言される。 outer = 10 # この場合 outer は宣言されず、外のスコープのouterが上書きされる。 inner = changeNumbers() # inner は10になる CoffeeScript の出力は (function(){ ... })(); で囲まれる。可変長引数(Splats)可変長の引数を取りたいときは変数名に「 ... 」を付ける。race = (winner, runners...) -> print winner, runners ... 」を使える。gold = silver = rest = "unknown" awardMedals = (first, second, others...) -> gold = first silver = second rest = others contenders = [ "Michael Phelps" "Liu Xiang" "Yao Ming" "Allyson Felix" "Shawn Johnson" "Roman Sebrle" "Guo Jingjing" "Tyson Gay" "Asafa Powell" "Usain Bolt" ] awardMedals contenders... 配列内包(Array comprehensions)と範囲指定(Range)Pythonのように配列内包表記ができる。 JavaScriptのforループと異なり、配列内包は式なので値(配列)を返す。 eachやforEach, map, select, filterなど色んなループ処理で配列内包を使える。 cubes = (math.cube num for num in list) eat food for food in ['toast', 'cheese', 'wine'] # 注:eatは関数。eat(food) になる。最初と最後の値が分かっているなら、配列内包で範囲記法(Range)が使える。 countdown = (num for num in [10..1]) 関数の最後で、単に副作用するループで終わる場合、意図せず配列内包の結果を返してしまわないように注意。 そのような場合は関数の最後で何か明示的に値(trueやnull)を返すようにするとよい。 内包表記はオブジェクトのキーと値を回すのにも使える。 配列の値ではなくオブジェクトのプロパティを渡すときは「 in 」ではなく「of 」を使う。yearsOld = max: 10, ida: 9, tim: 11 もし、何らかの理由で「 for (key in obj) ... 」というループを使いたいときは、代わりに「for all key, value of object 」という書き方をする。配列の範囲指定抽出・置換配列から一部を取り出すのに範囲表記(Range)が使える。 2つのドットは最後の値を含む:例えば (3..6) は (3, 4, 5, 6) になる。3つのドットは最後の値を含まない:例えば (3...6) は (3, 4, 5) になる。numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 配列の一部を置き換えるのにも範囲指定記法が使える。 numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] numbers[3..6] = [-3, -4, -5, -6] ただし、文字列では範囲指定置換は使えない。(範囲指定取り出しはできる) 全ては式(できるだけ)関数の return は不要で、代わりに最後の値が返される。CoffeScriptでは全ての文を「式」として扱える(できるだけそうしようとしている)。 例えば、以下のように関数の最後のif文は値を返す。 grade = (student) -> if student.excellentWork "A+" else if student.okayStuff if student.triedHard then "B" else "B-" else "C" eldest = if 24 > 21 then "Liz" else "Ike" 関数は常に最後の値を返すが、明示的に return を書く事で関数の途中で値を返すこともできる。 式の中では、初めて出てきた変数にも(varで宣言しなくても)代入できる。実際にコンパイルされたJavaScriptではスコープの最初で変数宣言されている。 six = (one = 1) + (two = 2) + (three = 3) # => 6 CoffeeScriptでは式になるが、JavaScriptでは式にならないような文はクロージャーでラップすることにより式に変換される。 そうすることで、例えば配列内包の結果を変数に入れるといったことができる。 # The first ten global properties. globals = (name for name of window)[0...10] try/catch文も引数として渡すことができる。 alert( try nonexistent / undefined catch error "And the error is ... " + error ) ただし、breakやcontinue、returnなど、式に変換できないJavaScriptの文もある。 CoffeeScriptではそのような文は変換されない。 存在演算子(Existential Operator)JavaScriptで変数に値が入っているかどうかを調べるのはやや面倒で、「 if (variable) 」だけだと値が0や空文字, falseのときも偽になるのでうまくいかない。CoffeeScriptの存在演算子「 ? 」を使うと、(Rubyっぽく)値がnullやundefined以外の時は true を返すようになる。数値や文字列などを条件付き代入するのにも使える。 solipsism = true if mind? and not world? speed ?= 75 footprints = yeti ? "bear" プロパティの値が null やundefined かもしれないとき、プロパティチェーンをドット「.」でつなぐ代わりに「?」を使える。もし全てのプロパティが存在すれば普通に結果が返ってくるし、チェーンが途中で途切れればTypeErrorが発生する代わりにundefinedが返る。 zip = lottery.drawWinner?().address?.zipcode ## 訳注:lotteryオブジェクトにdrawWinnerメソッドが存在し、そのメソッドの返り値にaddressプロパティが存在すればzipcodeを返す クラス, 継承, superJavaScriptのプロトタイプの継承は少しやりにくい。Base2、Prototype.js、JS.Classといったライブラリでは標準的なクラスの継承っぽい書き方ができるようになっている。これらのライブラリではいずれも継承のためのシンタックスシュガーを使えるが、素のJavaScriptの継承機能では super (親メソッド)を呼びにくく、プロトタイプチェーンを保ったまま継承しにくい。関数を何度もプロトタイプに加えていく代わりに、CoffeeScriptでは class の中でクラス名や親クラス、プロトタイプのプロパティ、コンストラクタなどを簡単に書ける。また、リフレクションをしやすくするためコンストラクタ関数には名前がつけられる。下のサンプルコードの最初のクラス(Animal)では「 this.constructor.name is "Animal" 」は真となる。class Animal constructor: (@name) -> move: (meters) -> alert @name + " moved " + meters + "m." class Snake extends Animal move: -> alert "Slithering..." super 5 class Horse extends Animal move: -> alert "Galloping..." super 45 sam = new Snake "Sammy the Python" tom = new Horse "Tommy the Palomino" sam.move() tom.move() JavaScriptの標準的なプロトタイプを書くが苦手な人向けに、ローレベルな便利機能がある。 「 extends 」演算子で簡単にプロトタイプを設定することができ、さらに「:: 」でオブジェクトのプロトタイプにアクセスできる(下の例)。また、「 super() 」で同名の親メソッドを呼べる。String::dasherize = -> this.replace /_/g, "-" クラス定義は(動的に)実行可能なコードで、面白いメタプログラミングもできる。 クラス定義の中では「this(もしくは@)」はクラスオブジェクト自身(コンストラクタ関数)であり、「 @property: value 」で静的変数(クラス変数)に代入でき、「@attr 'title' 」のようにして親クラスで定義された関数を呼べる。(ちょっと分かりにくいので追記すると)インスタンス変数、インスタンスメソッド、クラス変数、クラスメソッドはそれぞれ以下のように定義する。 class Hoge someInstanceProp: "hoge" # インスタンス変数 someInstanceMethod: -> # インスタンスメソッド @callAnotherInstanceMethod() # インスタンスメソッドを呼ぶ alert @someInstanceProp # ==> "hoge" @someClassProp: "hogehoge" # クラス変数 @someClassMethod: -> # クラスメソッド @callAnotherClassMethod() # 同一クラスのクラスメソッドを呼ぶ alert @someClassProp # ==> "hogehoge" 分割代入複雑な配列やオブジェクトから簡単に値を取り出すのに、CoffeeScriptではECMAScript Harmonyの分割代入記法を使える。下の例のように、配列やオブジェクトを別の値(配列やオブジェクト)に代入すると、右の値と左の変数がお互いマッチするように代入することができる。最も単純な利用法としては、並列代入に使える。 theBait = 1000 theSwitch = 0 [theBait, theSwitch] = [theSwitch, theBait] # => theBaitは0に、theSwitchは1000になる 多値を返す関数で使うと便利。 weatherReport = (location) -> # Make an Ajax request to fetch the weather... [location, 72, "Mostly Sunny"] [city, temp, forecast] = weatherReport "Berkeley, CA" 分割代入は配列やオブジェクトがネストしていても使うことができ、深い階層の値も取り出せる。 futurists = sculptor: "Umberto Boccioni" painter: "Vladimir Burliuk" poet: name: "F.T. Marinetti" address: [ "Via Roma 42R" "Bellagio, Italy 22021" ] {poet: {name, address: [street, city]}} = futurists 分割代入は可変長引数(splats)とも併せて使える。 tag = "<impossible>" [open, contents..., close] = tag.split("") 関数バインディングJavaScriptでは、「this」は関数が属しているオブジェクトを指す。関数をコールバックとして渡したり、別のオブジェクトに移動したら、 this の元の値は失われる。 CoffeeScriptでは太い矢印 「=>」 も関数定義に使うことができ、その場に this を束縛できる。この機能は、PrototypeやjQueryのようなコールバック関数を用いるライブラリで、eachのようなイテレータやイベントハンドラを渡すとき便利である。太い矢印「 => 」で定義された関数は、それが定義された場所の this のプロパティを参照できる。Account = (customer, cart) -> @customer = customer @cart = cart $('.shopping_cart').bind 'click', (event) => @customer.purchase @cart もし上の例でコールバック関数の定義に「 -> 」を使うと、@customer は未定義(undefined)のcustomerプロパティを参照し、purchase() の呼び出しで例外を投げる。JavaScriptの埋め込みできれば使わないに越したことはないが、JavaScriptのコードをCoffeeScriptの中で使いたいときは、バッククオート「`」で囲むとよい。 hi = `function() { return [document.title, "Hello JavaScript"].join(": "); }` JavaScriptのSwitch文は少し厄介で、うっかり次のcaseに飛んでしまわないように、全てのcase文の最後でbreakする必要がある。CoffeeScriptではbreakが無くても次のcaseに飛んでしまわないようになっており、代入で使うときはswitch文が値を返すようになっている。 switch文の書式は「switch 条件、when節、else デフォルトケース」となる。 Rubyのように、CoffeeScriptのwhen節は複数の値を取ることができる(下の例の when "Fri", "Sat")。もしいずれかの値にマッチしたらその節が実行される。 switch day when "Mon" then go work when "Tue" then go relax when "Thu" then go iceFishing when "Fri", "Sat" if day is bingoDay go bingo go dancing when "Sun" then go church else go work Try, Catch, Finallytry/catch文はJavaScriptとほぼ同じ(ただしCoffeeScriptでは式として使える)。 try allHellBreaksLoose() catsAndDogsLivingTogether() catch error print error finally cleanUp() 連結比較式Pythonのように連結比較式を使うことができ、値がある範囲内にあるかどうかを簡単に調べられる。 cholesterol = 127 healthy = 200 > cholesterol > 60 文字列中の式展開, ヒアドキュメント, ブロックコメントRubyと同様に文字列中の式展開ができる。 #{ ... } を使うことで、ダブルクオートされた文字列の中に変数や式を書ける。シングルクオート文字列の中では、 #{ ... } も文字列として扱われる。author = "Wittgenstein" quote = "A picture is a fact. -- #{ author }" sentence = "#{ 22 / 7 } is a decent approximation of π" 複数行の文字列も使える。 mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world..." ヒアドキュメントは、改行やインデントが重要なテキストを書くのに使われる。 ヒアドキュメント内のインデントは開始位置( ''' )に揃えられるため、コード全体のインデントを崩さない。html = ''' <strong> cup of coffeescript </strong> ''' ダブルクオートヒアドキュメント( """ で囲まれた複数行文字列)では、ダブルクオート文字列と同様に #{ ... } で式展開ができる。ブロックコメント( ### で囲まれた複数行コメント)は生成されたJavaScript内にそのまま表示される。ファイルの先頭にライセンスを埋め込みたい場合など、生成されたJavaScriptにコメントを残したいときに使える。 ### CoffeeScript Compiler v1.0.1 Released under the MIT License ### 拡張正規表現ヒアドキュメントやヒアコメントと同様に、CoffeeScriptではヒア正規表現(heregexes)も使える。 Perlの /x 修飾子のような拡張正規表現で、正規表現中の空白文字を無視し、正規表現中にコメントを書ける。ただしCoffeeScriptでは /x 修飾子の代わりに /// で正規表現を囲む。ヒア正規表現を使うことで、複雑な正規表現を読みやすくすることができる。 以下、CoffeeScriptのソースからの引用: OPERATOR = /// ^ ( ?: [-=]> # function | [-+*/%<>&|^!?=]= # compound assign / compare | >>>=? # zero-fill right shift | ([-+:])\1 # doubles | ([&|<>])\2=? # logic / shift | \?\. # soak access | \.{2,3} # range or splat ) /// |
CoffeeScript >