Is there a way to avoid using 'call' in Coffeescript?
I'm writing a simple Twitter client to play with coffeescript. I have an object literal with some functions that call each other via callbacks.
somebject =
foo: 'bar'
authenticateAndGetTweets: ->
console.log "Authorizing using oauth"
oauth = ChromeExOAuth.initBackgroundPage(this.oauthdetails)
oauth.authorize( this.afterLogin.call this )
afterLogin: ->
this.getTweets(this.pollinterval)
This code works perfectly. Edit: actually this.afterlogin should be sent as a callback above, not ran immediately, as Trevor noted below.
If, within authenticateAndGetTweets, I removed the 'call' and just ran:
oauth.authorize( this.afterLogin )
and don't use 'call', I get the following error:
Uncaught TypeError: Object [object DOMWindow] has no method 'getTweets
Which makes sense, since 'this' in afterLogin is bound to the thing that initiated the callback rather than 'someobject' my object literal.
I was wondering if there's some magic in Coffeescript I could be doing instead of 'call'. Initially I thought using the '=>' but the code will give the same error as above if '=>' is used开发者_Go百科.
So is there a way I can avoid using call? Or does coffeescript not obviate the need for it? What made '=>' not work how I expected it to?
Thanks. I'm really enjoying coffeescript so far and want to make sure I'm doing things 'the right way'.
As matyr points out in his comments, the line
oauth.authorize( this.afterLogin.call this )
doesn't cause this.afterLogin
to be called as a callback by oauth.authorize
; instead, it's equivalent to
oauth.authorize this.afterLogin()
Assuming that you want this.afterLogin
to used as a callback by oauth.authorize
, megakorre's answer gives a correct CoffeeScript idiom. An alternative approach supported by many modern JS environments, as matyr points out, would be to write
oauth.authorize( this.afterLogin.bind this )
There's no CoffeeScript shorthand for this, partly because Function::bind
isn't supported by all major browsers. You could also use the bind
function from a library like Underscore.js:
oauth.authorize( _.bind this.afterLogin, this )
Finally, if you were to define someobject
as a class instead, you could use =>
to define afterLogin
such that it's always bound to the instance, e.g.
class SomeClass
foo: 'bar'
authenticateAndGetTweets: ->
console.log "Authorizing using oauth"
oauth = ChromeExOAuth.initBackgroundPage(this.oauthdetails)
oauth.authorize(this.afterLogin)
afterLogin: =>
this.getTweets(this.pollinterval)
someobject = new SomeClass
you can put a lambda in the function call like so
auth.authorize(=> @afterLogin())
You have to use either the call or apply methods because they set the scope of the function (the value of this). The error results because the default scope is the window
object.
精彩评论