How to use set methods to initialize instance variables via constructor in coffeescript

1.4k views Asked by At

I have a "class" in coffee script whose instance variables I want to initialize with instance methods that return a value via a callback, but it doesn't work as I had hoped:

  EventEmitter = require('events').EventEmitter

  class MyClass extends EventEmitter
    constructor: ->
      @datamember: setDatamember()

    setDatamember: ->
      someFunction (response) ->
        @datamember = response
        @emit 'init'

    getDatamember: ->
      return @datamember

  ----

  myObj = new MyClass
  myObj.on 'init', ->
    console.log myObj.getDatamember

The result I get suggests that "this" in setDatamember is referring to something different from what "this" refers to in the object instance. If I explicitly call myObj.setDatamember, I get the expected result, but is there any way to call on a set method -- specifically one that sets the data member via a callback -- in the constructor? I've looked through the docs, as well as various other sources of coffeescript info (e.g. this one), and I haven't found anything that touches upon this.

2

There are 2 answers

0
Aaron Dufour On BEST ANSWER

Try using a fat arrow for the anonymous function:

setDatamember: ->
  someFunction (response) =>
    @datamember = response
    @emit 'init'

Also, you'll need to call the correct function in the constructor:

constructor: ->
  @setDatamember()

In general, avoid fat arrows on methods - the way Coffee-Script implements this does some bad things to memory usage. Also, it will rarely be necessary.

However, anonymous functions that refer to this will almost always need fat arrows. this is not held in closure like normal variables, and will only be set by binding (Function.prototype.bind) or by calling it as an object method (obj.myMethod() will set this to obj in myMethod).

5
Peter Lyons On

Try using fat arrows on everything except the constructor:

 class MyClass
    constructor: ->
      @setDatamember()

    setDatamember: =>
      someFunction (response) =>
        @datamember = response

    getDatamember: =>
      return @datamember

However, you also look to have someFunction in there as an asynchronous function, so you'll never be able to just do

mc = new MyClass
console.log mc.datamember

Because that doesn't wait for someFunction to return before accessing mc.datamember.