开发者

CoffeeScript Encapsulation and Variable Access

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 开发者_StackOverflow中文版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:

  1. 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?

  2. @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?

  3. @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:

  1. 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.
  2. Within the class body, @ 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.)
  3. Since @ 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜