Инкапсуляция 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 '------------'
Здесь происходят некоторые странные вещи:
-
x var
Я ожидал получить доступ к нему из любого метода, но x var не может быть доступен из любого метода или конструктора (ReferenceError). Я могу получить доступ к нему только из экземпляра A или B (i.x). Почему это?
-
@y var
Я ожидал получить значение @y var из любого метода, но он не имеет значения в большинстве мест (значение undefined, а не исключение ReferenceError). @y имеет значение только для @get3 и @get4 (методы экземпляра?). Если он определен, почему я не могу получить его значение?
-
@y и @z var
Оба @y и @z являются переменными экземпляра, но поскольку в конструкторе @z инициализировался, он имеет дифференцированное поведение. @y действует на @get3 и @get4, а @z действует на get и get2. Опять же, что здесь происходит?
Дело в том, что я действительно смущен этим поведением. Правильно ли этот код? Итак, следует ли мне больше узнать о JS, сгенерированном CS?
Tks
Ответы
Ответ 1
В телах функций @
относится к this
и в определениях классов @
относится к самому классу, а не к прототипу.
Итак, в приведенном выше примере определение @y
относится к A.y
, а не A.prototype.y
. Сложно ссылаться на него из-за того, что путь this
связан различными способами определения методов. Вы можете получить доступ к нему с помощью @y
из методов с именем @get
, потому что в этом случае this
всегда ссылается на A
.
Определение x
относится к A.prototype.x
, и поэтому из ваших методов get
вы должны получить к нему доступ через @x
в get1
и 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
EDIT: вы можете рассматривать методы, определенные как @something
как статические методы этого класса, поэтому вы можете вызывать их с помощью classname.something()
, но как статические методы, они не могут получить доступ к любому экземпляру переменные.
Ответ 2
Чтобы ответить на ваши вопросы:
-
x = 1
внутри тела класса создаст переменную с именем x
внутри тела области видимости. Но x: 1
внутри тела класса определяет свойство x
на прототипе. Если вы измените console.log x
на console.log @x
, вы получите 1
.
- Внутри тела класса
@
указывает на сам класс. Внутри конструктора (и в методах, называемых instance.method
), он указывает на конкретный экземпляр. Измените console.log @y
на console.log A.y
, и вы получите 2
. (Вы также можете использовать @constructor
, чтобы получить ссылку на класс из экземпляра, потому что в JavaScript класс фактически является конструкторской функцией.)
- Так как
@
в конструкторе указывает на экземпляр, вы устанавливаете для свойства экземпляра z
заданное значение.
И да, я рекомендую понять базовый JavaScript-я знаю, что это немного странно для @
, чтобы иметь так много разных значений, но это имеет большой смысл, как только вы понимаете JavaScript this
(один из сложнейших части языка, конечно). Кстати, моя книга имеет намного больше информации об этом.