CoffeeScriptの@について再び

コンテキストによってthisの内容が変わるという問題を回避するために必要な

that = this

実はこれなしでも済む記法がCoffeeScriptには存在することに気がついた。

「=>」(fat arrow)

手元のソースコードから修正箇所を抜粋。

before
    that = this
    @window.addEventListener("focus", (e)-> that.refreshTable())
after
    @window.addEventListener("focus", (e)=> @refreshTable())

おわかりいただけただろうか。

関数定義の時に「->」ではなく「=>」を使うことで、冗長な「that = this」が不要になるわけだ。とてもスマートなわけだ。

JavaScript的に見ると

「=>」を使うとJavaScriptのコードの頭で「__bind」という関数が定義されて、このからくりを可能にしている。

var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

applyとはこのように使うものなのですね。

そしてこの__bindを次のように使っている。

    this.window.addEventListener("focus", __bind(function(e) {
      return this.refreshTable();
    }, this));

すげえぜ!

実コードはともかくJasmineでスペックで「that = this」をたくさん書いていたので、これはうれしい仕組み。
CoffeeScriptを使わない場合でも「that = this」の増殖を回避する方法はあるというわけで、勉強になった。

常に「=>」を使うってのはどうなの?

あれこれ「->」の方いらなくね?
って一瞬思ってしまったが、よく考えるとthisが何を指しているかを意識して使い分けることは必要っぽい。

例えば以前のCoffeeScriptの@の話で書いた以下のコードでは、xhr.onloadの関数定義に安易に「=>」を使うとthisの指すものが逆に意図通りではなくなる。

class SomeAPI
    @items: []
 
    @searchItem: ->
        that = this
        xhr = Ti.Network.createHTTPClient()
 
        url = "http://api.example.com/?query=hogehoge"
        xhr.open('GET', url)
 
        xhr.onload = ->
            doc = this.responseXML.documentElement
            that.items = doc.getElementsByTagName('Item')
 
        xhr.onerror = (err) ->
            alert("ネットワークからデータを取得できませんでした。")
 
        xhr.send()

このケースならxhr.onload内のthisをxhrにしたらいけたりしないのかしらとか突っ込みどころはあるが、「=>」を使わない方が楽に書ける場面もあるだろうということで。

あと「->」より「=>」の方が関数呼び出しが余計に挟まるので、パフォーマンス的にもちょっとはオーバーヘッドがあるはず。
ちりも積もればレベルの微々たるものとは思うけど。

というわけで「=>」は意図的に必要なときだけ使っておくのがいいんじゃないのという結論に達したわけだ。