How do I call an instance method from within a closure?
I am trying to access an instance method inside a call map
, unfortunately my instance object reference is being overridden in Window. I am not sure how to get my instance method:
class Test
constructor: (@an_array) ->
f: () ->
@an_array.map (value) ->
@a(value)
a: (value) ->
alert value
t = new Test [1, 2, 3]
t.f() // TypeError: Object [object Window] has no method 'a'
source to share
There are various ways to deal with this.
The most common in CoffeeScript would be to use the bold arrow ( =>
) to create a bound function:
@an_array.map (value) => @a(value)
Demo: http://jsfiddle.net/ambiguous/6BW8q/
Standard JavaScript approaches will also work (and sometimes are necessary or more appropriate):
-
Save the reference
@
to not worry about whatthis
's inside the callback function:_this = @ @an_array.map (value) -> _this.a(value)
Demo: http://jsfiddle.net/ambiguous/XhP4z/
I prefer to use
_this
insteadself
as a name for this thing because of the existencewindow.self
and interesting errors that are thrown if you forgetvar
in JavaScript. -
Manually create a bound function using
Function.bind
, this is not entirely universally supported:@an_array.map ((value) -> @a(value)).bind(@)
-
Use jQuery
$.proxy
, Underline_.bind
or some other unrelated features of related functions:@an_array.map _((value) -> @a(value)).bind(@)
Which one you choose depends on your environment and specific needs:
- If you are trying to link a function that comes from other sources then you cannot use
=>
, so you have to use some variant (2) or (3) above (or maybeFunction.call
orFunction.apply
). - If you need both internal and external
this
at the same time, you should go with (1) . - If you need to manually bind a function, but you're not sure if a native exists
bind
, then you will probably get (3) and which branch (3) will probably depend on which library you already have. - ...
- Profit.
source to share
It turned out that I can do this by specifying a variable to keep the reference to this
:
class Test
constructor: (@an_array) ->
f: () ->
self = @
@an_array.map (value) ->
self.a(value)
a: (value) ->
alert value
t = new Test [1, 2, 3]
t.f() // raises 3 alerts: 1, 2, 3
This seems a little hacky, so I'll leave the Q&A for someone to teach me how this should be done.: D
source to share