javascriptでprivate変数へのアクセサをクラスに定義する関数

関数本体

Object.attr_accessor = function(obj, name, initval) {
  obj[name] = (function() {
     var value;
     return function() {
       return arguments.length ? value = arguments[0] : value;
     };
  })();
  if (initval) obj[name](initval);
  return obj;
};

Object.attr_reader = function(obj, name, initval) {
   Object.attr_accessor(obj, name, initval);
   var _attr = obj[name];
   obj[name] = function(){ return _attr.call() };
}

オブジェクトにprivateなプロパティとsetter, getterを定義する。
プロパティに引数有りでアクセスした場合setterになり、
引数無しの場合getterとなる。setterの場合も戻り値はgetterと同じ。

使い方

// クラスに追加
var MyClass = function(){};
MyClass.prototype = {
  attr: function() {
    return Object.attr_accessor.apply(null,
      [this].concat(Array.prototype.slice.call(arguments, 0))
    );
  },

  attr_r: function() {
    return Object.attr_reader.apply(null,
      [this].concat(Array.prototype.slice.call(arguments, 0))
    );
  }
}

// オブジェクト毎にアクセサを追加
var obj = new MyClass();
obj.attr("test");
obj.test("hogehoge");
alert(obj.test()); //-> 「hogehoge」

// 追加と同時に初期化も行う
obj.attr("test2", 100);
alert(obj.test2()); //-> 「100」

クラスに追加せずにObject.attr_accessor(obj, "propname")としてやっても良い。

コンストラクタでアクセサ定義

var MyClass2 = function(){
   this.attr("test");
   this.attr("test2", 500);
}
MyClass2.prototype.attr = function() {
    return Object.attr_accessor.apply(null,
      [this].concat(Array.prototype.slice.call(arguments, 0))
    );
};

var obj2 = new MyClass2();
obj2.test("hogehoge");
alert(obj2.test()); //-> 「hogehoge」
alert(obj2.test2()); //-> 「500」

readonlyにする

var MyClass3 = function(){
  this.attr_r("test", "foobar");
}
MyClass3.prototype.attr = function(name, init) {
  return Object.attr_reader.apply(null, [this, name, init]);
}

var obj3 = new MyClass3();
alert(obj.test()); //-> 「foobar」
alert(obj.test("overwrite")); //-> 「foobar」

readonlyで定義すると内部からの書き換えもできないし、
そうでないと外からも書き換え自由だし、使いどころがわからない。。。
java好きの為のsetter, getterといったところか。

クラス内からだけ書き換えられて外からはreadonlyにできたら理想だけど。