Matt Fletcher
Matt Fletcher

Reputation: 9220

Coffeescript incorrect scope of @ when passing method as callback

When I pass an anonymous function with fat arrows as a socket.io callback and then call another method in the same object (as follows) the scope of @ is correct:

module.exports = class InviteCreateSocket extends AbstractSocket
  register: () ->
    @socket.on 'invite:create', (data, callback) => @create data, callback

  create: (data = {}, callback = @_noop) ->
    # This returns an instantiated InviteCreateSocket. Bonzer!
    console.log @

However, if I pass it in directly, the scope is now of the socket, as if I had run the previous code with thin arrows:

module.exports = class InviteCreateSocket extends AbstractSocket
  register: () ->
    @socket.on 'invite:create', @create

  create: (data = {}, callback = @_noop) ->
    # This returns the socket. Not bonzer. Not bonzer at all.
    console.log @

So, is there a nice clean way of getting object scope without having to relay them through a fat anonymous function? The first method works but seems a bit clumsy and obviously requires having to synchronise the parameters in all the methods. Thanks in advance!

Upvotes: 0

Views: 184

Answers (2)

Exinferis
Exinferis

Reputation: 687

Why not use the fat arrow for the functions belonging to the class, thus binding them correctly to the context of the class (and it's instances) - this is more how it is intended to work.

module.exports = class InviteCreateSocket extends AbstractSocket
  register: () =>
    @socket.on 'invite:create', @create
    return

  create: (data = {}, callback = @_noop) =>
    console.log @
    return

Also, don't forget to add empty returns in function which are not intended to return something.

Upvotes: 3

Amadan
Amadan

Reputation: 198324

Not a Coffeescript expert, but I'd guess no. It's because Coffeescript is compiled to JavaScript, and JavaScript equivalent is going against you. The issue is this: you can't have a reference to a method, because to be a method it has to be invoked on a recipient.

var bar = foo.create;
bar();

is very different than

foo.create();

because the former does not set this to foo. So when you just pass @create, it dissociates your method from your object, and @ is not correct any more within your method-that-is-now-just-a-function.

Now, back to CoffeeScript: the uglier way to solve your parameter dilemma is => @create(arguments...). This should pass all arguments to @create, whatever they are. However, the nicer way to do it is to simulate what the fat arrow does using a plain JS technique: @create.bind(@).

There may be something nicer by someone more knowledgeable in CoffeeScript, though.

Upvotes: 2

Related Questions