Scoping issue with prototypes and async.forEach

I have a scope issue that I don't understand.

I have this object with some methods:

FileInfo = (file) ->
   @name = path.basename(file.path);

FileInfo::uploadImage = (filename, callback) ->

FileInfo::handleImage = (version, callback) ->
   # Here I would like to call uploadImage

I am calling handleImage from an async.forEach loop as:

async.forEach options, fileInfo.handleImage,  (err) -

I would like to call uploadImage from within handleImage but I get TypeError: Object # has no method 'uploadImage'

I have tried, inside of handleImage, the following:

this.uploadImage

as well as:

that = this
that.uploadImage

Neither work.

If I call fileInfo.handleImage outside of the forEach loop it works fine with either this or that.

Change fileInfo.handleImage to fileInfo.handleImage.bind(fileInfo) (assuming fileInfo is an instance of FileInfo).

It is losing the this binding (that is, the value of this when that function is executing, not to be confused with the execution context, see comments) that you expect, because you don't immediately invoke it, just pass a reference to it.

You can either use bind as suggested above or the fat arrow (=>)

However for the fat arrow to work you need to use idiomatic Coffeescript classes. Building a class the normal Javascript way by assigning prototype slots wont work.

class FileInfo
    constructor: (file) -> 
        @name = path.basename(file.path);

    uploadImage: (filename, callback) ->

                                     ---- fat arrow here
                                     V
    handleImage: (version, callback) =>
    # Here I would like to call uploadImage

Using it that way will force the CoffeeScript compiler to generate the binding in Javascript for you.