第3回: 関数定義と分割代入

2012/03/05

前回は、jQuery UIの話が中心でした。

今回は、CoffeeScriptの関数の使い方について書きます。

リファクタリング

現在、app/assets/javascripts/top.js.coffee はこうなっています。

$ ->
  $("div#canvas").dblclick (e) ->
    canvas = $(e.target)
    x = e.pageX - canvas.position().left
    y = e.pageY - canvas.position().top
    block = $("<div class='block' style='left: #{x}px; top: #{y}px;' />").
      draggable(containment: "parent").css(position: "absolute")
    canvas.append(block)

イベントハンドラのコードがちょっと長いので、関数として分離しましょう。次のように修正してください。

$ ->
  $("div#canvas").dblclick (e) ->
    [x, y] = positionOfNewBlock(e)
    block = $("<div class='block' style='left: #{x}px; top: #{y}px;' />").
      draggable({ containment: "parent" }).css({ position: "absolute" })
    $(e.target).append(block)

positionOfNewBlock = (e) ->
  canvas = $(e.target)
  x = e.pageX - canvas.position().left
  y = e.pageY - canvas.position().top
  [x, y]

プログラム全体の振る舞いはまったく変わりません。純然たるリファクタリングです。

関数の定義

まず、後半部分から見ていきましょう。

positionOfNewBlock = (e) ->
  canvas = $(e.target)
  x = e.pageX - canvas.position().left
  y = e.pageY - canvas.position().top
  [x, y]

慣れない間はちょっと変な感じがするかもしれませんが、これがCoffeeScriptにおける関数の定義です。

posiionOfNewBlock が関数名、(e) が引数リスト、-> 以下が関数の本体です。

関数本体の3行目までは、修正前のソースコードのコピーです。4行目の [x, y] は、Rubyプログラマには馴染み深い書き方です。関数本体の中でで最後に評価された式の値が関数の戻り値となります。純粋なJavaScriptであれば return [x, y] と書くべきところです。大括弧 [ ]配列を作って、それを返しています。

分割代入

前半部分で変更されたのは次の1行です:

    [x, y] = positionOfNewBlock(e)

positionOfNewBlock(e) で、先ほど説明した関数を呼び出しています。

興味深いのは、[x, y] = ... という形で2つのローカル変数 x, y に値をセットしていることです。

実は、CoffeeScript では次のような書き方が可能なのです。

[a, b] = [1, 2]

これは、ローカル変数 a に 1 を、b に 2 をセットするということです。

また、こんな書き方もできます。

[a, b] = [b, a]

これは、ローカル変数 a, b の値を交換します。

これを分割代入(destructuring assignment)と呼び、CoffeeScriptの重要な特長です。

なお、Rubyでは次のような書き方ができますが、CoffeeScriptではシンタックスエラーになります。

a, b = 1, 2

逆に、[a, b] = [1, 2] という書き方はRubyではシンタックスエラーになります。

また、次の書き方もRubyではOKですが、CoffeeScriptではNGです。

return x, y