LoginSignup
20
19

More than 5 years have passed since last update.

contextを使ってfat arrowなメソッドを書きなおそう

Last updated at Posted at 2012-12-26

Backbone.jsとCoffeeScriptをお使いのみなさん、こんにちは。

イベントのcallbackに登録するメソッドをfat arrowで定義してませんか?
Backbone.Events#onの3番目の引数contextを使いましょう。

メソッドをfat arrowで定義するとmixin出来ない問題についてもちょこっと触れます。

  • イベント通知のために、グローバルなPubSubが定義されています。
  • NyaModel#initializeで、NyaModel#sayMessageメソッドをPubSubに登録しています。
  • PubSubから(」・ω・)」うー!イベントを受け取ると、NyaModel#sayMessageが呼ばれます。
  • NyaModel#sayMessageは、NyaModelmessage属性をコンソールに出力します。

今までの僕のfat arrowなやりかた

PubSubのcallbackに渡すメソッドの中でNyaModelの属性を使いたい。
だがしかしPubSubのcallback関数中ではthisPubSubになる。
thisNyaModelに固定するため、メソッドをfat arrow(=>)で定義してた。

nyaru.coffee
window.PubSub = _.clone(Backbone.Events)

class NyaModel extends Backbone.Model
  defaults:
    message: '(/・ω・)/にゃー!'

  initialize: ->
    PubSub.on '(」・ω・)」うー!', @sayMessage

  # thisがNyaModelにbindされるようfat arrowで定義
  sayMessage: =>
    console.log @get('message')

PubSub.on '(」・ω・)」うー!', ->
  console.log '(」・ω・)」うー!'

new NyaModel
PubSub.trigger '(」・ω・)」うー!'
PubSub.trigger '(」・ω・)」うー!'

new NyaModel message: "Let's\(・ω・)/にゃー!"
PubSub.trigger '(」・ω・)」うー!'

# (」・ω・)」うー!
# (/・ω・)/にゃー!
# (」・ω・)」うー!
# (/・ω・)/にゃー!
# (」・ω・)」うー!
# (/・ω・)/にゃー!
# Let's\(・ω・)/にゃー!

contextを使ったfat arrowじゃないやりかた

Backbone.Events#onの第3引数でcontextを与えると、callback関数中のthisがcontextになります。
これでfat arrowを使う理由がなくなった。

nyaru.coffee
window.PubSub = _.clone(Backbone.Events)

class NyaModel extends Backbone.Model
  defaults:
    message: '(/・ω・)/にゃー!'

  initialize: ->
    # contextとして@を渡してあげる
    PubSub.on '(」・ω・)」うー!', @sayMessage, @

  # context渡すとthisがNyaModelになるのでfatじゃなくておk
  sayMessage: ->
    console.log @get('message')

PubSub.on '(」・ω・)」うー!', ->
  console.log '(」・ω・)」うー!'

new NyaModel
PubSub.trigger '(」・ω・)」うー!'
PubSub.trigger '(」・ω・)」うー!'

new NyaModel message: "Let's\(・ω・)/にゃー!"
PubSub.trigger '(」・ω・)」うー!'

# (」・ω・)」うー!
# (/・ω・)/にゃー!
# (」・ω・)」うー!
# (/・ω・)/にゃー!
# (」・ω・)」うー!
# (/・ω・)/にゃー!
# Let's\(・ω・)/にゃー!

fat arrowのままでもいいじゃないの?

確かに今までの例だとその通りです。

しかしfat arrowのままだとmixinなどでsayMessageを入れ替えたいときに問題が生じます。

fat arrowはmixinできない

fat arrowなmethodをmixinするとき、同じようにfat arrowを使ってこう書くのは間違いです

_.extend NyaModel::
  sayMessage: =>
    console.log "(」・ω・)」うー! #{@get('message')}"

これは次のようなJavaScriptに展開されます。

var _this = this;

_.extend(NyaModel.prototype, {
  sayMessage: function() {
    return console.log("(」・ω・)」うー! " + (_this.get('message')));
  }
});

thisがトップレベル、ブラウザだとwindowオブジェクトにbindされてしまいます。

しかしfat arrowをやめると、(」・ω・)」うー!イベントで呼び出された際に、thisPubSubになってしまうのでエラーが出ます。

nyaru.coffee
window.PubSub = _.clone(Backbone.Events)

class NyaModel extends Backbone.Model
  defaults:
    message: '(/・ω・)/にゃー!'

  initialize: ->
    PubSub.on '(」・ω・)」うー!', @sayMessage

  sayMessage: ->
    console.log @get('message')

_.extend NyaModel::
  sayMessage: ->
    console.log "(」・ω・)」うー! #{@get('message')}"

new NyaModel
PubSub.trigger '(」・ω・)」うー!'

# thisがPubSubにbindされちゃう><
# => TypeError: Object #<Object> has no method 'get'

contextがあればmixinも怖くない

nyaru.coffee
window.PubSub = _.clone(Backbone.Events)

class NyaModel extends Backbone.Model
  defaults:
    message: '(/・ω・)/にゃー!'

  initialize: ->
    PubSub.on '(」・ω・)」うー!', @sayMessage, @

  sayMessage: ->
    console.log @get('message')

_.extend NyaModel::
  # contextのおかげでthisがmodelになってる
  sayMessage: ->
    console.log "(」・ω・)」うー! #{@get('message')}"

new NyaModel
PubSub.trigger '(」・ω・)」うー!'
PubSub.trigger '(」・ω・)」うー!'

new NyaModel message: "Let's\(・ω・)/にゃー!"
PubSub.trigger '(」・ω・)」うー!'

# (」・ω・)」うー! (/・ω・)/にゃー!
# (」・ω・)」うー! (/・ω・)/にゃー!
# (」・ω・)」うー! (/・ω・)/にゃー!
# (」・ω・)」うー! Let's\(・ω・)/にゃー!

まとめ

  • Backbone.events#onの3番目の引数contextを渡すと、callback関数中のthiscontextにbindされる。
  • イベントのcallbackに渡すメソッド中のthisを固定するためにfat arrow(=>)を使う必要はありません。contextを使いましょう。
  • メソッドをfat arrowで定義すると、mixinできません。
    • 正確にはできるけどthisをbindしなおす必要があって面倒です。
20
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
19