CoffeeScript中的私人成员?
有人知道如何在CoffeeScript中创build私有的非静态成员吗? 目前我正在做这个,它只是使用一个以下划线开头的公共variables来澄清它不应该在类之外使用:
class Thing extends EventEmitter constructor: (@_name) -> getName: -> @_name
把variables放在类中使其成为一个静态成员,但是如何使它成为非静态的? 甚至有可能没有“看中”?
甚至有可能没有“看中”?
可悲的是,你必须要看中 。
class Thing extends EventEmitter constructor: (name) -> @getName = -> name
请记住, “这只是JavaScript”。
类只是函数,所以他们创build范围。 在这个范围内定义的所有东西都不会从外面看到。
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
Vitaly的答案有一个问题,那就是你不能定义你想对范围唯一的variables,如果你这样做了一个私有的名字,然后改变了它,那么名称值就会为每个类的实例改变,所以有一个办法可以解决这个问题
# 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
否则从外部访问names数组并不是不可能的
testing一下
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; };
这里是一个解决scheme,其中的几个其他答案,再加上https://stackoverflow.com/a/7579956/1484513 。 它将私有实例(非静态)variables存储在私有类(静态)数组中,并使用对象ID来知道该数组的哪个元素包含属于每个实例的数据。
# 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 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
以下是如何在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
咖啡脚本中的“类”导致基于原型的结果。 所以即使你使用一个私有variables,它也是在实例之间共享的。 你可以这样做:
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,所以您可以拥有私有variables的唯一方法是通过闭包。
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
当然这和所有其他的私有variables都有相同的限制,例如,新添加的方法不能访问它们,因为它们没有在同一个范围内定义。
使用CoffeeScript类不能轻松完成,因为它们使用Javascript构造函数模式来创build类。
不过,你可以这样说:
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类的伟大,因为你不能通过任何其他方式inheritance这个类,而不是使用extend()。 instanceof将停止工作,而以这种方式创build的对象消耗更多的内存。 另外,您不能再使用新的和超级关键字。
关键是,每次实例化类时都必须创build闭包。 纯CoffeeScript类中的成员闭包只创build一次 – 也就是说,构build类运行时“types”时。
以下是关于设置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
如果你只想从公开中分离出私人成员,只需将其包装在$ variable中即可
$: requirements: {} body: null definitions: null
并使用@$.requirements