Trying to understand how CoffeeScript instance and class variable works I came with this code (and the results are in the comments).
class A
x: 1
@y: 2
constructor: (@z) ->
#console.log "const x", x #ReferenceError: x is not defined
console.log "constructor y", @y #undefined
console.log "constructor z", @z # = 3 for A and 6 for B
get: () ->
#console.log "get x", x #ReferenceError: x is not defined
console.log "get y", @y #undefined
console.log "get z", @z # = 3 for A and 6 for B
get2: () =>
#console.log "get2 x", x #ReferenceError: x is not defined
console.log "get2 y", @y #undefined
console.log "get2 z", @z # = 3 for A and 6 for B
@get3: () ->
#console.log "get3 x", x #ReferenceError: x is not defined
console.log "get3 y", @y # = 2
console.log "get3 z", @z #undefined
@get4: () =>
#console.log "get4 x", x #ReferenceError: x is not defined
console.log "get4 y", @y # = 2
console.log "get4 z", @z #undefined
class B extends A
constructor: (@w) ->
super(@w)
console.log '------A------'
i = new A 3
console.log "i.x", i.x # = 1
console.log "i.y", i.y #undefined
console.log "i.z", i.z # = 6
i.get()
i.get2()
A.get3()
A.get4()
console.log '------B------'
i = new B 6
console.log "i.x", i.x # = 1
console.log "i.y", i.y #undefined
console.log "i.z", i.z # = 6
console.log "i.w", i.w # = 6
i.get()
i.get2()
B.get3()
B.get4()
console.log '------------'
There are some strange things happening here:
x var I was expecting to access it from any method but x var can't be accessed from any method or constructor (ReferenceError). I'm only able to access it from a instance of A or B (i.x). Why is that?
@y var I was expecting to get @y var value from any method but it has no value in most of places (undefined value, not a ReferenceError exception). @y has value only on @get3 and @get4 (instance methods?). If it is defined, why I can't get its value?
@y and @z var Both @y and @z are instance variables, but because @z was initialized in the constructor, it has a differentiated behavior. @y is valid on @get3 and @get4 and @z is valid on get and get2. Again, what is happening here?
The thing is that I'm really confused by these behaviors. Is this code correct? So, should I learn more about JS generated by CS?
Tks
In function bodies, @
refers to this
and in class definitions, @
refers to the class itself rather than the prototype.
So in the example above, the definition of @y
refers to A.y
, and not A.prototype.y
. It's tricky to refer to it because of the way this
is bound in the various ways of defining methods. You can access it using @y
from methods named @get
because in this case this
always refers to A
.
The definition of x
refers to A.prototype.x
and so from your get
methods you should access it via @x
in get1
and get2
.
As a basic guide, try not to use @
outside of function bodies and everything will make a lot more sense:
class A
constructor: (@a) ->
b: 2
tryStuff: =>
console.log(@a) #will log whatever you initialized in the constructor
console.log(@b) #will log 2
EDIT: you could consider methods defined as @something
to be static methods of that class, so you can call them with classname.something()
but as static methods, they can't access any instance variables.
To respond to your questions:
x = 1
within the class body would create a variable named x
within the scope body. But x: 1
within the class body defines a property x
on the prototype. If you change console.log x
to console.log @x
, then you'll get 1
.@
points to the class itself. Within the constructor (and in methods called as instance.method
), it points to the particular instance. Change console.log @y
to console.log A.y
, and you'll get 2
. (You can also use @constructor
to get a reference to the class from the instance, because in JavaScript, the class actually is the constructor function.)@
in the constructor points to the instance, you're setting the instance's z
property to the given value.And yes, I do recommend understanding the underlying JavaScript—I know it's a bit odd for @
to have so many different meanings, but it makes a lot of sense once you understand JavaScript's this
(one of the trickier parts of the language, to be sure). Incidentally, my book has a lot more info on this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With