CoffeeScript封装和变量访问

时间:2011-07-01 18:34:15

标签: coffeescript

尝试理解CoffeeScript实例和类变量如何工作我带了这段代码(结果在评论中)。

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 '------------'

这里发生了一些奇怪的事情:

  1. x var 我期望从任何方法访问它,但无法从任何方法或构造函数(ReferenceError)访问x var。我只能从A或B(i.x)的实例访问它。那是为什么?

  2. @y var 我期望从任何方法获得@y var值,但它在大多数地方没有值(未定义的值,不是ReferenceError异常)。 @y仅对@ get3和@ get4(实例方法?)有价值。如果它被定义,为什么我不能得到它的价值?

  3. @y和@z var @y和@z都是实例变量,但由于@z在构造函数中初始化,因此它具有不同的行为。 @y在@ get3和@ get4上有效,@ z在get和get2上有效。再次,这里发生了什么?

  4. 事情是我对这些行为感到困惑。这段代码是否正确?那么,我应该更多地了解CS生成的JS吗?

    韩国社交协会

2 个答案:

答案 0 :(得分:16)

在函数体中,@引用this,在类定义中,@引用类本身而不是原型。

因此,在上面的示例中,@y的定义是A.y,而不是A.prototype.y。由于this在定义方法的各种方式中的约束方式,引用它很棘手。您可以使用名为@y的方法中的@get来访问它,因为在这种情况下,this始终引用A

x的定义是指A.prototype.x,因此您应get方法通过@xget1中的get2访问它。

作为基本指南,尽量不要在函数体之外使用@,一切都会更有意义:

class A
  constructor: (@a) ->
  b: 2
  tryStuff: =>
    console.log(@a) #will log whatever you initialized in the constructor
    console.log(@b) #will log 2

编辑:您可以将定义为@something的方法视为该类的静态方法,因此您可以使用classname.something()调用它们,但作为静态方法,它们可以' t访问任何实例变量。

答案 1 :(得分:9)

回答你的问题:

    类体中的
  1. x = 1将在范围体内创建一个名为x的变量。但是,类主体中的x: 1在原型上定义了属性x。如果您将console.log x更改为console.log @x,那么您将获得1
  2. 在班级团体中,@指向班级本身。在构造函数(以及称为instance.method的方法)中,它指向特定实例。将console.log @y更改为console.log A.y,您将获得2。 (您也可以使用@constructor从实例获取对类的引用,因为在JavaScript中,类实际上构造函数。)
  3. 由于构造函数中的@指向实例,因此您将实例的z属性设置为给定值。
  4. 是的,我建议理解基础JavaScript - 我知道@有很多不同的含义有点奇怪,但是一旦你理解了JavaScript的this,它就会很有意义。这是语言中比较棘手的部分之一。顺便提一下,my book有更多关于此的信息。