4

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.

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'.

3
  • I did, but didn't understand your code. this.afterLogin.call this calls it immediately (it's identical to @afterLogin()), where this.afterLogin retrieves the function. Are you sure you aren't looking for Function::bind? Commented May 28, 2011 at 18:51
  • Matyr I mentioned I was already using 'call' in the title of the question, so saying 'use call' wasn't really much of an answer. Your second question makes a good point though: I'm actually running a function rather than specifying a function to run as a callback (which is what I want to do). I'll check this out now. Commented May 29, 2011 at 15:14
  • Uh yes, I meant "Why .call? You mean .bind?" Sorry for confusing you further. Commented May 30, 2011 at 3:08

3 Answers 3

3

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
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks Trevor for your comprehensive answer: I do actually want this.afterLogin to be run as a callback, with 'this' set to the object the afterlogin is part of.
Cool, see expanded answer for a couple more ideas.
Thanks again Trevor: using an object literal vs using a class also answers my second question re: why => wasn't working as I expected.
3

you can put a lambda in the function call like so

auth.authorize(=> @afterLogin())

1 Comment

Thanks, wrapping in a lambda works too - upboat! However in this case I always want the function to be called with this as the object it's a property of, so @Trevor's suggestion of using a class and => is more appropriate.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.