【问题标题】:CoffeeScript Encapsulation and Variable AccessCoffeeScript 封装和变量访问
【发布时间】:2011-09-26 23:18:43
【问题描述】:

为了了解 CoffeeScript 实例和类变量的工作原理,我附带了这段代码(结果在 cmets 中)。

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 变量 我期望从任何方法访问它,但不能从任何方法或构造函数(ReferenceError)访问 x var。我只能从 A 或 B (i.x) 的实例访问它。这是为什么呢?

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

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

问题是我对这些行为感到非常困惑。这段代码正确吗?那么,我应该多了解CS生成的JS吗?

Tks

【问题讨论】:

    标签: coffeescript


    【解决方案1】:

    回答您的问题:

    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 有更多关于这方面的信息。

    【讨论】:

    • 谢谢!顺便说一句,我已经预订了你的书 :D 希望很快就能买到!
    【解决方案2】:

    在函数体中,@ 指的是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() 调用它们,但作为静态方法,它们无法访问任何实例变量。

    【讨论】:

    • 太棒了!我认为最重要的是:“作为基本指南,尽量不要在函数体之外使用@,一切都会变得更有意义”没错!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多