Вопрос

Кто-нибудь знает, как сделать частных, нестатических участников в CoffeeScript? В настоящее время я делаю это, которая просто использует общественную переменную, начиная с подчеркивания, чтобы уточнить, что ее не следует использовать вне класса:

class Thing extends EventEmitter
  constructor: (@_name) ->

  getName: -> @_name

Размещение переменной в классе делает ее статическим участником, но как я могу сделать ее нестатическим? Возможно ли это даже без «фантазии»?

Это было полезно?

Решение

Возможно ли это даже без «фантазии»?

Грустно сказать, ты должен быть изысканный.

class Thing extends EventEmitter
  constructor: (name) ->
    @getName = -> name

Запомнить, «Это просто javascript».

Другие советы

Классы - это просто функции, поэтому они создают прицелы. Все, что определено внутри этой области, не будет видно снаружи.

class Foo
  # this will be our private method. it is invisible
  # outside of the current scope
  foo = -> "foo"

  # this will be our public method.
  # note that it is defined with ':' and not '='
  # '=' creates a *local* variable
  # : adds a property to the class prototype
  bar: -> foo()

c = new Foo

# this will return "foo"
c.bar()

# this will crash
c.foo

CoffeeScript объединяет это в следующее:

(function() {
  var Foo, c;

  Foo = (function() {
    var foo;

    function Foo() {}

    foo = function() {
      return "foo";
    };

    Foo.prototype.bar = function() {
      return foo();
    };

    return Foo;

  })();

  c = new Foo;

  c.bar();

  c.foo();

}).call(this);

Я хотел бы показать что -то еще более причудливое

class Thing extends EventEmitter
  constructor: ( nm) ->
    _name = nm
    Object.defineProperty @, 'name',
      get: ->
        _name
      set: (val) ->
        _name = val
      enumerable: true
      configurable: true

Теперь вы можете сделать

t = new Thing( 'Dropin')
#  members can be accessed like properties with the protection from getter/setter functions!
t.name = 'Dragout'  
console.log t.name
# no way to access the private member
console.log t._name

Есть одна проблема с ответом Виталия, и вы не можете определить переменные, которыми вы хотите быть уникальный К прицеле, если вы так сделали личное имя, а затем изменили его, значение имени изменится для каждого отдельного экземпляра класса, поэтому мы можем решить эту проблему.

# create a function that will pretend to be our class 
MyClass = ->

    # this has created a new scope 
    # define our private varibles
    names = ['joe', 'jerry']

    # the names array will be different for every single instance of the class
    # so that solves our problem

    # define our REAL class
    class InnerMyClass 

        # test function 
        getNames: ->
            return names;

    # return new instance of our class 
    new InnerMyClass

Невозможно получить доступ к массиву имен извне, если вы не используете getNames

Проверьте это

test = new MyClass;

tempNames = test.getNames()

tempNames # is ['joe', 'jerry']

# add a new value 
tempNames.push 'john'

# now get the names again 
newNames = test.getNames();

# the value of newNames is now 
['joe', 'jerry', 'john']

# now to check a new instance has a new clean names array 
newInstance = new MyClass
newInstance.getNames() # === ['joe', 'jerry']


# test should not be affected
test.getNames() # === ['joe', 'jerry', 'john']

Скомпилированный JavaScript

var MyClass;

MyClass = function() {
  var names;
  names = ['joe', 'jerry'];
  MyClass = (function() {

    MyClass.name = 'MyClass';

    function MyClass() {}

    MyClass.prototype.getNames = function() {
      return names;
    };

    return MyClass;

  })();
  return new MyClass;
};

Вот решение, которое опирается на несколько других ответов здесь плюс https://stackoverflow.com/a/7579956/1484513. Анкет В нем хранится частный экземпляр (нестатический) переменные в массиве частного класса (статический) и использует идентификатор объекта, чтобы узнать, какой элемент этого массива содержит данные, принадлежащие каждому экземпляру.

# Add IDs to classes.
(->
  i = 1
  Object.defineProperty Object.prototype, "__id", { writable:true }
  Object.defineProperty Object.prototype, "_id", { get: -> @__id ?= i++ }
)()

class MyClass
  # Private attribute storage.
  __ = []

  # Private class (static) variables.
  _a = null
  _b = null

  # Public instance attributes.
  c: null

  # Private functions.
  _getA = -> a

  # Public methods.
  getB: -> _b
  getD: -> __[@._id].d

  constructor: (a,b,@c,d) ->
    _a = a
    _b = b

    # Private instance attributes.
    __[@._id] = {d:d}

# Test

test1 = new MyClass 's', 't', 'u', 'v'
console.log 'test1', test1.getB(), test1.c, test1.getD()  # test1 t u v

test2 = new MyClass 'W', 'X', 'Y', 'Z'
console.log 'test2', test2.getB(), test2.c, test2.getD()  # test2 X Y Z

console.log 'test1', test1.getB(), test1.c, test1.getD()  # test1 X u v

console.log test1.a         # undefined
console.log test1._a        # undefined

# Test sub-classes.

class AnotherClass extends MyClass

test1 = new AnotherClass 's', 't', 'u', 'v'
console.log 'test1', test1.getB(), test1.c, test1.getD()  # test1 t u v

test2 = new AnotherClass 'W', 'X', 'Y', 'Z'
console.log 'test2', test2.getB(), test2.c, test2.getD()  # test2 X Y Z

console.log 'test1', test1.getB(), test1.c, test1.getD()  # test1 X u v

console.log test1.a         # undefined
console.log test1._a        # undefined
console.log test1.getA()    # fatal error

Вот Лучшая статья, которую я нашел о настройке public static members, private static members, public and private members, и некоторые другие связанные вещи. Он охватывает много деталей и js против. coffee сравнение. И для исторический Причины вот лучший пример кода:

# CoffeeScript

class Square

    # private static variable
    counter = 0

    # private static method
    countInstance = ->
        counter++; return

    # public static method
    @instanceCount = ->
        counter

    constructor: (side) ->

        countInstance()

        # side is already a private variable, 
        # we define a private variable `self` to avoid evil `this`

        self = this

        # private method
        logChange = ->
            console.log "Side is set to #{side}"

        # public methods
        self.setSide = (v) ->
            side = v
            logChange()

        self.area = ->
            side * side

s1 = new Square(2)
console.log s1.area()   # output 4

s2 = new Square(3)
console.log s2.area()   # output 9

s2.setSide 4            # output Side is set to 4
console.log s2.area()   # output 16

console.log Square.instanceCount() # output 2

Вот как вы можете объявить частных, нестатических участников в CoffeeScript
Для получения полной ссылки вы можете взглянуть на https://github.com/vhmh2005/jsclass

class Class

  # private members
  # note: '=' is used to define private members
  # naming convention for private members is _camelCase

  _privateProperty = 0

  _privateMethod = (value) ->        
    _privateProperty = value
    return

  # example of _privateProperty set up in class constructor
  constructor: (privateProperty, @publicProperty) ->
    _privateProperty = privateProperty

«Класс» в кофейных сценариях приводит к результатам на основе прототипа. Таким образом, даже если вы используете частную переменную, она разделяется между экземплярами. Ты можешь это сделать:

EventEmitter = ->
  privateName = ""

  setName: (name) -> privateName = name
  getName: -> privateName

.. ведет к

emitter1 = new EventEmitter()
emitter1.setName 'Name1'

emitter2 = new EventEmitter()
emitter2.setName 'Name2'

console.log emitter1.getName() # 'Name1'
console.log emitter2.getName() # 'Name2'

Но будьте осторожны, чтобы поставить частных участников перед публичными функциями, потому что сценарий кофе возвращает публичные функции в качестве объекта. Посмотрите на скомпилированный JavaScript:

EventEmitter = function() {
  var privateName = "";

  return {
    setName: function(name) {
      return privateName = name;
    },
    getName: function() {
      return privateName;
    }
  };
};

Поскольку сценарий кофе компилируется в JavaScript, единственный способ иметь личные переменные - это закрытие.

class Animal
  foo = 2 # declare it inside the class so all prototypes share it through closure
  constructor: (value) ->
      foo = value

  test: (meters) ->
    alert foo

e = new Animal(5);
e.test() # 5

Это будет компилироваться через следующий JavaScript:

var Animal, e;
Animal = (function() {
  var foo; // closured by test and the constructor
  foo = 2;
  function Animal(value) {
    foo = value;
  }
  Animal.prototype.test = function(meters) {
    return alert(foo);
  };
  return Animal;
})();

e = new Animal(5);
e.test(); // 5

Конечно, это имеет все те же ограничения, что и все другие личные переменные, которые вы можете иметь, с помощью закрытия, например, вновь добавленные методы не имеют к ним доступа, поскольку они не были определены в одной и той же области.

Вы не можете сделать это легко с классами CoffeeScript, потому что они используют шаблон конструктора JavaScript для создания классов.

Однако вы можете сказать что -то вроде этого:

callMe = (f) -> f()
extend = (a, b) -> a[m] = b[m] for m of b; a

class superclass
  constructor: (@extra) ->
  method: (x) -> alert "hello world! #{x}#{@extra}"

subclass = (args...) -> extend (new superclass args...), callMe ->
  privateVar = 1

  getter: -> privateVar
  setter: (newVal) -> privateVar = newVal
  method2: (x) -> @method "#{x} foo and "

instance = subclass 'bar'
instance.setter 123
instance2 = subclass 'baz'
instance2.setter 432

instance.method2 "#{instance.getter()} <-> #{instance2.getter()} ! also, "
alert "but: #{instance.privateVar} <-> #{instance2.privateVar}"

Но вы теряете величие классов CoffeeScript, потому что вы не можете унаследовать от класса, созданного таким образом другим способом, чем с помощью extend () снова. случай перестанет работать, и objecs создал этот путь, потребляет немного больше памяти. Кроме того, вы не должны использовать новый а также супер Ключевые слова больше.

Дело в том, что закрытие должно создаваться каждый раз, когда класс создается. Закрытие участников в чистых классах CoffeeScript создается только один раз, то есть, когда строится тип выполнения класса «тип».

Если вы хотите, чтобы только отдельные частные члены от публики просто оберните его в $ variable

$:
        requirements:
              {}
        body: null
        definitions: null

и использовать @$.requirements

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top