CoffeeScript의 비공개 멤버?
누군가 CoffeeScript에서 비공개 비 정적 멤버를 만드는 방법을 알고 있습니까? 현재 저는 클래스 외부에서 사용해서는 안된다는 것을 명확히하기 위해 밑줄로 시작하는 공용 변수를 사용하는이 작업을 수행하고 있습니다.
class Thing extends EventEmitter
constructor: (@_name) ->
getName: -> @_name
클래스에 변수를 넣으면 정적 멤버가되지만 어떻게 비 정적으로 만들 수 있습니까? "멋지다"지 않고도 가능할까요?
"멋지다"지 않고도 가능할까요?
슬프게도, 당신은 멋져 야 합니다.
class Thing extends EventEmitter
constructor: (name) ->
@getName = -> name
기억 "그냥 자바 스크립트입니다."
클래스는 함수일 뿐이므로 범위를 만듭니다. 이 범위 내에 정의 된 모든 것은 외부에서 볼 수 없습니다.
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의 대답에는 한 가지 문제가 있으며 범위에 고유 하고 싶은 변수를 정의 할 수 없다는 것입니다. 그렇게 개인 이름을 만든 다음 변경하면 이름 값이 클래스의 모든 인스턴스에 대해 변경됩니다. 그 문제를 해결할 수있는 한 가지 방법이 있습니다
# 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']
컴파일 된 자바 스크립트
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을 추가하는 솔루션이 있습니다 . 프라이빗 인스턴스 (비 정적) 변수를 프라이빗 클래스 (정적) 배열에 저장하고 객체 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 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;
}
};
};
Since coffee script compiles down to JavaScript the only way you can have private variables is through closures.
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
This will compile down through the following 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
Of course this has all the same limitations as all the other private variables you can have through the use of closures, for example, newly added methods don't have access to them since they were not defined in the same scope.
You can't do it easily with CoffeeScript classes, because they use the Javascript constructor pattern for creating classes.
However, you could say something like this:
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}"
But you lose the greatness of CoffeeScript classes, because you can't inherit from a class created that way by any other way than by using extend() again. instanceof will stop working, and objecs created this way consume a little bit more memory. Also, you mustn't use the new and super keywords anymore.
The point is, that the closures must be created every time a class is instantiated. The member closures in pure CoffeeScript classes are created only once - that is, when the class runtime "type" is constructed.
If you want only separate private memebers from public, just wrap it in $ variable
$:
requirements:
{}
body: null
definitions: null
and use @$.requirements
참고URL : https://stackoverflow.com/questions/4685626/private-members-in-coffeescript
'IT story' 카테고리의 다른 글
선택한 모든 확인란의 jQuery 배열 (클래스 별) (0) | 2020.09.17 |
---|---|
문자열 리소스에 공백 적용 (0) | 2020.09.17 |
기본 MySQL JOIN 동작, INNER 또는 OUTER는 무엇입니까? (0) | 2020.09.16 |
세그먼트 화 오류 (코어 덤프) 란 무엇입니까? (0) | 2020.09.16 |
우편 배달부를 사용하여 특정 요청을 파일로 내보내는 방법 (0) | 2020.09.16 |