Eric Acevedo
Eric Acevedo

Reputation: 1222

Coffeescript classes and scope

While learning coffeescript, I'm trying to create an instance of class A inside a method of class B, this is the code:

class @A
  constructor: (@x) ->
  show: ->
    alert @x

class @B
  constructor: (@y) ->
  show: ->
    a = new @A("eric")
    alert a.x
    alert @y

b = new @B("daniel")
b.show()

the error is TypeError: undefined is not a function. Any help is appreciated.

Thanks

Upvotes: 0

Views: 34

Answers (1)

mu is too short
mu is too short

Reputation: 434615

You have two problems:

  1. @ is just another way of saying this in CoffeeScript. That's all it means.
  2. Classes are (more or less) just variables or properties like any other in CoffeeScript.

So when you say @A, you're just looking for the A property of this and your show is really saying:

a = new this.A("eric")

In that context, @ will be an instance of B and Bs don't have A properties. Instead you should just say:

a = new A('eric')

Using @ when defining a class:

class @A
  #...

is just a way to make a class globally available. At the top level, @ will (almost always) be window in a browser so you're really saying:

class window.A
  #...

and window properties are globals. Keep in mind that each CoffeeScript file is wrapped in a function when it is converted to JavaScript:

Although suppressed within this documentation for clarity, all CoffeeScript output is wrapped in an anonymous function: (function(){ ... })(); This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult to pollute the global namespace by accident.

So if you just said:

class A

then A would only be available to other code in that file. Saying:

class @A

makes A global.

If you're only working with one file then you don't need the @s on your classes:

class A
  constructor: (@x) ->
  show: ->
    alert @x

class B
  constructor: (@y) ->
  show: ->
    a = new A("eric")
    alert a.x
    alert @y

b = new B("daniel")
b.show()

Don't get in the habit of prefixing everything with @, only use it on classes when you need it and you know exactly what it will do. Even when you need it, there are better ways: use require.js to manage your dependencies, use an global application-specific object to manage scopes, ...

Upvotes: 1

Related Questions