2011-07-01 11 views
14

Próbuję zrozumieć, jak działa instancja klasy i instancji klasy CoffeeScript, więc przyszedł z tym kodem (a wyniki są w komentarzach).Enkapsulacja CoffeeScript i zmienny dostęp

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

Istnieją pewne dziwne rzeczy się tu dzieje:

  1. x var Spodziewałem się do niego dostęp z dowolnego sposobu x var lecz nie mogą być dostępne z dowolnej metody lub konstruktora (ReferenceError) . Mogę uzyskać do niego dostęp tylko z instancji A lub B (i.x). Dlaczego?

  2. @y var Spodziewałem się uzyskać wartość @y var z dowolnej metody, ale nie ma ona wartości w większości miejsc (wartość niezdefiniowana, a nie wyjątek ReferenceError). @y ma wartość tylko na @ get3 i @ get4 (metody instancji?). Jeśli jest zdefiniowany, dlaczego nie mogę uzyskać jego wartości?

  3. @y i @z var Zarówno @y jak i @z są zmiennymi instancji, ale ponieważ @z został zainicjowany w konstruktorze, ma on zróżnicowane zachowanie. @ y jest poprawne na @ get3 i @ get4, a @z jest poprawne na get i get2. Znowu, co się tutaj dzieje?

Chodzi o to, że jestem naprawdę zdezorientowany tymi zachowaniami. Czy ten kod jest poprawny? Czy powinienem dowiedzieć się więcej o JS generowanym przez CS?

TKS

Odpowiedz

15

W treściach funkcji @ odnosi się do this, aw definicjach klas, @ odnosi się do samej klasy, a nie do prototypu.

Tak więc w powyższym przykładzie definicja @y odnosi się do A.y, a nie A.prototype.y.Trudno się na to odnieść ze względu na sposób wiązania się na różne sposoby definiowania metod. Dostęp do niego można uzyskać, korzystając z metod o nazwie @get, ponieważ w tym przypadku this zawsze odnosi się do A.

Definicja x dotyczy A.prototype.x i tak ze swoimi metodami get należy do niego dostęp za pośrednictwem @x w get1 i get2.

Jako podstawowy przewodnik, staraj się nie używać @ poza organami funkcyjnymi i wszystko będzie dużo więcej sensu:

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: można rozważyć metody zdefiniowane jako @something być metody statyczne tej klasy, aby można było wywoływać je przy pomocy classname.something(), ale jako metody statyczne, nie mogą uzyskać dostępu do żadnych zmiennych instancji.

+0

Świetnie! Myślę, że najważniejsza jest tutaj: "Jako podstawowy przewodnik, staraj się nie używać @ poza ciałami funkcyjnymi i wszystko będzie miało więcej sensu" Prawda! –

8

Aby odpowiedzieć na pytania:

  1. x = 1 w ciele klasy byłoby utworzyć zmienną o nazwie x w organizmie zakres. Ale x: 1 w treści głównej definiuje właściwość x na prototypie. Jeśli zmienisz console.log x na console.log @x, otrzymasz 1.
  2. W treści klasy @ wskazuje na samą klasę. Wewnątrz konstruktora (oraz w metodach zwanych jako instance.method) wskazuje on konkretną instancję. Zmień console.log @y na console.log A.y, a otrzymasz 2. (Można również użyć @constructor uzyskać referencję do klasy z instancji, ponieważ w JavaScript, klasa faktycznie jest funkcja konstruktora.)
  3. Od @ w punktach konstruktora instancji, jesteś ustawienie właściwość z instancji do podanej wartości.

I tak, ja polecam zrozumienia bazowego JavaScript-wiem, że to trochę dziwne dla @ mieć tak wiele różnych znaczeń, ale to sprawia, że ​​wiele sensu, jeżeli rozumie JavaScript na this (jeden z trudniejszych części języka, aby mieć pewność). Nawiasem mówiąc, my book ma o wiele więcej informacji na ten temat.

+1

Tks! I BTW, już wcześniej zamówiłem twoją książkę: D Hope, aby ją zdobyć wkrótce! –