CoffeeScript封装和变量访问

Dav*_*Sb. 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 '------------'
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

TKS

nic*_*ten 16

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

所以在上面的例子中,定义是@yA.y,而不是A.prototype.y.引用它是很棘手的,因为这种方式this在定义方法的各种方式中受到限制.您可以使用@y命名的方法访问它,@get因为在这种情况下this始终引用A.

从你的方法中x引用的定义是你应该通过in 和.A.prototype.xget@xget1get2

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

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

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


Tre*_*ham 9

回答你的问题:

  1. x = 1在类体内将创建一个x在范围体内命名的变量.但是x: 1在类体内定义了x原型上的属性.如果更改console.log xconsole.log @x,那么你会得到1.
  2. 在类体内,@指向类本身.在构造函数(以及称为as的方法instance.method)中,它指向特定实例.更改console.log @yconsole.log A.y,你会得到2.(您还可以使用@constructor从实例获取对类的引用,因为在JavaScript中,类实际上构造函数.)
  3. 由于@在构造函数中指向实例,因此您将实例的z属性设置为给定值.

是的,我建议理解底层的JavaScript - 我知道@有这么多不同的含义有点奇怪,但是一旦你理解了JavaScript this(这个语言的一个比较棘手的部分,确定)它会很有意义..顺便说一下,我的书有很多关于此的信息.