Prywatni członkowie w CoffeeScript?

Czy ktoś wie jak zrobić prywatne, niestatyczne członków w CoffeeScript? Obecnie robię to, co po prostu używa publicznej zmiennej zaczynającej się od podkreślenia, aby wyjaśnić, że nie powinna być używana poza klasą:

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

  getName: -> @_name

Umieszczenie zmiennej w klasie sprawia, że jest ona członkiem statycznym, ale jak mogę uczynić ją nie-statyczną? Czy to w ogóle możliwe bez "fantazji"?

Author: Nathan Arthur, 2011-01-14

11 answers

Czy to w ogóle możliwe bez "fantazji"?
Przykro mi to mówić, ale musiałbyś być fantazyjny .
class Thing extends EventEmitter
  constructor: (name) ->
    @getName = -> name

Pamiętaj, " to tylko JavaScript."

 20
Author: matyr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-13 23:02:14

Klasy są tylko funkcjami, więc tworzą zakresy. wszystko zdefiniowane wewnątrz tego zakresu nie będzie widoczne z zewnątrz.

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 kompiluje to w następujący sposób:

(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);
 204
Author: Vitaly Kushner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-22 05:25:45

Chciałbym pokazać coś jeszcze bardziej fantazyjnego

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

Teraz możesz zrobić

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
 10
Author: Tim Wu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-28 03:38:33

Jest jeden problem z odpowiedzią Vitaly ' ego i jest to, że nie możesz zdefiniować zmiennych, które chcesz mieć unikalne do zakresu, jeśli zrobiłeś prywatną nazwę w ten sposób, a następnie ją zmieniłeś, wartość nazwy zmieniłaby się dla każdej pojedynczej instancji klasy, więc jest jeden sposób, w jaki możemy rozwiązać ten problem

# 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

Dostęp do tablicy nazw nie jest niemożliwy z zewnątrz, chyba że użyjesz getNames

Przetestuj to

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

Skompilowany 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;
};
 2
Author: iConnor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-24 03:37:26

Oto rozwiązanie, które czerpie z kilku innych odpowiedzi tutaj plus https://stackoverflow.com/a/7579956/1484513 . przechowuje prywatne instancje (niestatyczne) zmiennych w tablicy klasy prywatnej (statycznej) i używa ID obiektu, aby wiedzieć, który element tej tablicy zawiera dane należące do każdej instancji.

# 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
 2
Author: Waz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:39

Oto najlepszy artykuł jaki znalazłem o ustawieniu public static members, private static members, public and private members, i inne podobne rzeczy. Obejmuje wiele szczegółów i js vs. coffee Porównanie. A dla historycznych oto najlepszy przykład kodu z niego:

# 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
 2
Author: plunntic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-01 14:41:39

Oto jak możesz zadeklarować prywatne, niestatyczne członkowie w Coffeescript
Dla pełnego odniesienia, można spojrzeć na 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
 1
Author: Hung Vo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-17 08:47:14

"klasa" w skryptach kawowych prowadzi do wyniku opartego na prototypie. Więc nawet jeśli używasz zmiennej prywatnej, jest ona współdzielona między instancjami. Możesz to zrobić:

EventEmitter = ->
  privateName = ""

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

.. prowadzi do

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

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

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

Ale uważaj, aby umieścić prywatnych członków przed funkcjami publicznymi, ponieważ coffee script zwraca funkcje publiczne jako obiekt. Spójrz na skompilowany Javascript:

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

  return {
    setName: function(name) {
      return privateName = name;
    },
    getName: function() {
      return privateName;
    }
  };
};
 1
Author: Stefan Dohren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-06 15:42:54

Ponieważ coffee script kompiluje się do JavaScript, jedynym sposobem na posiadanie prywatnych zmiennych jest zamknięcie.

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

To skompiluje się poprzez następujący 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

Oczywiście ma to takie same ograniczenia jak wszystkie inne zmienne prywatne, które możesz mieć poprzez użycie zamknięć, na przykład nowo dodane metody nie mają do nich dostępu, ponieważ nie zostały zdefiniowane w tym samym zakresie.

 0
Author: Ivo Wetzel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-13 22:06:12

Nie można tego łatwo zrobić z klasami CoffeeScript, ponieważ używają one wzorca konstruktora Javascript do tworzenia klas.

Można jednak powiedzieć coś takiego:

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}"

Ale tracisz wielkość klas CoffeeScript, ponieważ nie możesz dziedziczyć po klasie utworzonej w ten sposób w inny sposób niż przez ponowne użycie extend (). instanceof przestanie działać, a obiekty utworzone w ten sposób zużywają trochę więcej pamięci. Ponadto, nie wolno używać Nowe isuper słowa kluczowe.

Chodzi o to, że zamknięcia muszą być tworzone za każdym razem, gdy klasa jest tworzona. Zamknięcia prętów w klasach Pure CoffeeScript są tworzone tylko raz - to znaczy, gdy jest skonstruowana Klasa runtime "type".

 0
Author: Jaakko Salomaa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-02 21:18:53

Jeśli chcesz oddzielić tylko prywatne memebery od publicznych, po prostu zawiń je w $ zmienna

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

I używać @$.requirements

 -3
Author: borovsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-19 16:11:20