Quelqu'un sait-il comment créer des membres privés et non statiques dans CoffeeScript? Actuellement, je fais cela, qui utilise simplement une variable publique commençant par un trait de soulignement pour clarifier qu'elle ne doit pas être utilisée 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 la rendre non statique? Est-ce même possible sans «fantaisie»?
name
n'est visible que de l'intérieur de la fermeture du constructeur. Regardez ceci: gist.github.com/803810@getName = -> name
semble rompre tout héritage possible de lagetName
fonction.getName
est public, etname
n'est accessible qu'à partir de la fonction constructeur, donc ce n'est pas vraiment "privé" pour l'objet.les classes ne sont que des fonctions, elles créent donc des portées. tout ce qui est défini à l'intérieur de cette portée 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 compile ceci comme suit:
(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);
la source
foo.call(this)
pourthis
être l'instance de la fonction. C'est pourquoi essayer d'émuler l'héritage classique en JavaScript devient poilu.var
déclarations internes qui les masqueront.J'aimerais montrer quelque chose d'encore plus chic
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
la source
Il y a un problème avec la réponse de Vitaly et c'est que vous ne pouvez pas définir les variables que vous voulez être uniques à la portée, si vous avez créé un nom privé de cette façon et que vous l'avez modifié, la valeur du nom changerait pour chaque instance de la classe, il y a donc une façon 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 de 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; };
la source
Voici une solution qui s'appuie sur plusieurs des autres réponses ici 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'objet 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 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
la source
Voici le meilleur article que je trouve sur l' établissement
public static members
,private static members
,public and private members
et d'autres choses connexes. Il couvre beaucoup de détails et parjs
rapport à lacoffee
comparaison. 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
la source
Voici comment déclarer des membres privés et 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
la source
«classe» dans les scripts café conduit à un résultat basé sur un prototype. Ainsi, 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 veillez à mettre les membres privés avant les fonctions publiques, car coffee script renvoie les fonctions publiques en tant qu'objet. Regardez le Javascript compilé:
EventEmitter = function() { var privateName = ""; return { setName: function(name) { return privateName = name; }, getName: function() { return privateName; } }; };
la source
Étant donné que le script coffee se compile en JavaScript, la seule façon d'avoir des variables privées est de fermer.
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 compilera via 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 les mêmes limitations que toutes les autres variables privées que vous pouvez avoir grâce à l'utilisation de fermetures, par exemple, les méthodes nouvellement ajoutées n'y ont pas accès car elles n'ont pas été définies dans la même portée.
la source
e = new Animal(5);f = new Animal(1);e.test()
alerte un, je veux cinq.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 pouvez 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 grandeur des classes CoffeeScript, car vous ne pouvez pas hériter d'une classe créée de cette manière autrement qu'en utilisant à nouveau extend (). instanceof cessera de fonctionner et les objets créés de cette manière consomment un peu plus de mémoire. De plus, vous ne devez plus utiliser les nouveaux et super mots clés.
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 de la classe est construit.
la source
Si vous voulez seulement séparer les membres privés du public, enveloppez-le simplement dans $ variable
$: requirements: {} body: null definitions: null
et utilise
@$.requirements
la source