Membres privés dans CoffeeScript?

Est-ce que quelqu’un sait comment faire des membres privés non statiques dans CoffeeScript? Actuellement, je le fais, qui utilise simplement une variable publique commençant par un trait de soulignement pour préciser qu’il ne devrait pas être utilisé en dehors de la classe:

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

Mettre la variable dans la classe en fait un membre statique, mais comment puis-je le rendre non statique? Est-ce que c’est possible sans avoir de “fantaisie”?

Est-ce que c’est possible sans avoir de “fantaisie”?

C’est sortingste à dire, il faut être chic .

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

Rappelez-vous que “c’est juste JavaScript”.

les classes ne sont que des fonctions afin de créer des étendues. tout ce qui est défini dans cette scope ne sera pas visible de l’extérieur.

 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 comstack ceci dans les cas suivants:

 (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); 

Je voudrais montrer quelque chose encore plus fantaisiste

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

Maintenant tu peux faire

 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 

Il y a un problème avec la réponse de Vitaly: vous ne pouvez pas définir des variables que vous voulez rendre uniques à la scope, si vous avez créé un nom privé et que vous l’avez modifié, la valeur du nom changera pour chaque instance de la classe. il y a donc un moyen de résoudre ce problème

 # 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 

Il n’est pas impossible d’accéder au tableau des noms depuis l’extérieur sauf si vous utilisez getNames

Testez ceci

 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 compilé

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

Voici une solution qui s’appuie sur plusieurs autres réponses, plus https://stackoverflow.com/a/7579956/1484513 . Il stocke les variables d’instance privée (non statiques) dans un tableau de classe privée (statique) et utilise un ID d’object pour savoir quel élément de ce tableau contient les données appartenant à chaque instance.

 # Add IDs to classes. (-> i = 1 Object.defineProperty Object.prototype, "__id", { writable:true } Object.defineProperty Object.prototype, "_id", { get: -> @__id ?= i++ } )() class MyClass # Private atsortingbute storage. __ = [] # Private class (static) variables. _a = null _b = null # Public instance atsortingbutes. c: null # Private functions. _getA = -> a # Public methods. getB: -> _b getD: -> __[@._id].d constructor: (a,b,@c,d) -> _a = a _b = b # Private instance atsortingbutes. __[@._id] = {d:d} # Test test1 = new MyClass 's', 't', 'u', 'v' console.log 'test1', test1.getB(), test1.c, test1.getD() # test1 tuv test2 = new MyClass 'W', 'X', 'Y', 'Z' console.log 'test2', test2.getB(), test2.c, test2.getD() # test2 XYZ console.log 'test1', test1.getB(), test1.c, test1.getD() # test1 X uv 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 tuv test2 = new AnotherClass 'W', 'X', 'Y', 'Z' console.log 'test2', test2.getB(), test2.c, test2.getD() # test2 XYZ console.log 'test1', test1.getB(), test1.c, test1.getD() # test1 X uv console.log test1.a # undefined console.log test1._a # undefined console.log test1.getA() # fatal error 

Voici le meilleur article que j’ai trouvé sur la création de public static members , private static members , private static members public and private members et d’autres éléments connexes. Il couvre beaucoup de détails et js vs comparaison de coffee . Et pour les raisons historiques , voici le meilleur exemple de code:

 # 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 

Voici comment vous pouvez déclarer des membres privés non statiques dans Coffeescript
Pour une référence complète, vous pouvez consulter 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 

“class” dans les scripts de café conduit à un résultat basé sur un prototype. Donc, même si vous utilisez une variable privée, elle est partagée entre les instances. Tu peux le faire:

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

.. mène à

 emitter1 = new EventEmitter() emitter1.setName 'Name1' emitter2 = new EventEmitter() emitter2.setName 'Name2' console.log emitter1.getName() # 'Name1' console.log emitter2.getName() # 'Name2' 

Mais attention à mettre les membres privés avant les fonctions publiques, car le script café renvoie les fonctions publiques en tant qu’object. Regardez le Javascript compilé:

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

Étant donné que le script de café se comstack en JavaScript, la seule façon d’avoir des variables privées est de passer par des fermetures.

 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 

Cela comstackra à travers le JavaScript suivant:

 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 

Bien sûr, cela a toutes les mêmes limitations que toutes les autres variables privées que vous pouvez avoir en utilisant des fermetures, par exemple, les méthodes nouvellement ajoutées n’y ont pas access car elles n’ont pas été définies dans la même scope.

Vous ne pouvez pas le faire facilement avec les classes CoffeeScript, car elles utilisent le modèle de constructeur Javascript pour créer des classes.

Cependant, vous pourriez dire quelque chose comme ceci:

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

Mais vous perdez la qualité des classes CoffeeScript, car vous ne pouvez pas hériter d’une classe créée de cette manière autrement qu’en utilisant extend (). instanceof cessera de fonctionner et les objecs créés de cette façon consumnt un peu plus de mémoire. De plus, vous ne devez plus utiliser les nouveaux mots clés et les mots clés super .

Le fait est que les fermetures doivent être créées chaque fois qu’une classe est instanciée. Les fermetures de membres dans les classes CoffeeScript pures ne sont créées qu’une seule fois, c’est-à-dire lorsque le type d’exécution “type” est construit.

Si vous ne voulez séparer que les membres privés, il suffit de l’envelopper dans $ variable

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

et utilisez @$.requirements