[oop] 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