2011-07-01 38 views
14

试图了解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 我期待从任何方法,但X访问var它不能从任何方法或构造访问(的ReferenceError) 。我只能从A或B(i.x)的实例访问它。这是为什么?我期待从任何方法获得@y var值,但它在大多数地方没有值(未定义的值,不是ReferenceError异常)。 @y仅在@ get3和@ get4(实例方法?)上具有值。如果定义了,为什么我不能得到它的价值?

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

事情是,我真的很困惑这些行为。这段代码是否正确?那么,我是否应该更多地了解由CS生成的JS?

韩国社交协会

回答

15

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

所以在上面的例子中,@y的定义是指A.y,而不是A.prototype.y。由于this被定义方法的各种方式所束缚,因此提及它非常棘手。您可以使用名为@get的方法使用@y来访问它,因为在这种情况下,this总是指A

x的定义是指A.prototype.x等从get方法,你应该在get1get2通过@x访问它。

作为一个基本的指导,尽量不要使用@外函数体的一切都会让很多更有意义:

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()来调用它们,但是作为静态方法,它们不能访问任何实例变量。

+0

太棒了!我认为最重要的是:“作为一个基本指南,尽量不要在功能体外使用@,一切都会变得更有意义”真实! –

8

要回复您的问题:

  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属性为给定值。

是的,我建议了解底层的JavaScript,我知道这是一个有点奇怪的@有这么多不同的含义,但它使一个很大的意义,一旦你理解JavaScript的this(较为复杂的地区之一的语言,当然)。顺便提一句,my book有更多的信息。

+1

Tks!顺便说一句,我已经预订了你的书:D希望尽快得到它! –