CoffeeScriptのプライベートメンバについてのメモ

はじめに

プライベートメンバについてメモ代わりに適当なサンプルを書いてみました。

サンプル

以下のCoffeeScriptから生成されたJavaScriptのコードを確認したいのであれば、CoffeeScriptの公式ページのTRY COFFEESCRIPTに以下のコードを貼りつけてください。

class Person
  # クラス変数
  @DEAD  = 0
  @ALIVE = 1

  # インスタンス変数はコンストラクタ引数で直接指定できる
  constructor: (@name, _age, _state=Person.ALIVE) ->
    # インスタンス変数。パブリック
    # @name

    # インスタンス変数。プライベート
    # _age, _state

    # インスタンスメソッド。プライベート。非共用
    _increment = ->
      ++_age

    # インスタンスメソッド。パブリック。非共用
    @getStatus = ->
      _state

    # インスタンスメソッド。パブリック。非共用
    @setStatus = (newStatus) ->
      _state = newStatus

    # インスタンスメソッド。パブリック。非共用
    @getAge = ->
      _age

    # インスタンスメソッド。パブリック。非共用
    @growUp = ->
      _increment() if _state is Person.ALIVE

  # インスタンスメソッド。パブリック。共用
  getName: ->
    @name

  # インスタンスメソッド。パブリック。共用
  setName: (newName) ->
    @name = newName


p1 = new Person 'yamada', 20
p2 = new Person 'kinjo', 30, Person.DEAD

# インスタンス変数nameの取得
# パブリックなのでどちらの方法でも取得できる
alert p1.getName()  # yamada
alert p2.name       # kinjo

# インスタンス変数_ageの取得
# プライベートなのでgetterからしか取得できない
alert p1.getAge()   # 20
alert p2._age       # undefined

# プライベート変数_ageの操作
# growUp()は内部で_increment()を呼び出している
p1.growUp()
alert p1.getAge()   # 21

# プライベート変数_ageの操作
# _increment()メソッドはプライベートなので直接呼び出せない
p2._increment()     # TypeError: Object #<Person> has no method '_increment'

上記のコードのようにプライベート変数(_age, _state)にアクセスするメソッドはconstructorの中で定義する必要があります。
また、コメントに書いてある共用・非共用というのはJavaScript側のコードを見ると解ると思います。以下のコードがその一部です。

Person = (function() {
  Person.DEAD = 0;
  Person.ALIVE = 1;
  function Person(name, _age, _state) {
省略
    this.getAge = function() {
      return _age;
    };
省略
  }
  Person.prototype.getName = function() {
    return this.name;
  };
省略

getNameプロパティはprototypeに追加されているので全てのインスタンスで共有されるためメモリ効率が良いです。しかし、getAgeプロパティは各インスタンスごとに持つので(非共有なので)メモリ効率が悪いです。ですが、この方法だとプライベート変数と同じスコープなのでアクセスすることが出来ます。