JavaScriptにはpublicやprivate等の概念は無いですがやはり、private相当の属性にはgetterやsetterを提供してやりたくなります。
余談ですが、プラべーメンバーの隠蔽はコンストラクター内でクロージャーを使用すれば実現可能ですが他のメンバー関数からも
直接参照出来なくなるので好みではありません(命名規則などのルールで拘束すれば十分だと思ってます)。
で、getterやsetterの実装を考えると高級言語によくあるpropertyは良くできた仕様です。
内部的にsetterを定義しないかreadonlyを宣言すれば参照のみ出来るメンバー変数のできあがりです。
[C#]
{
private int foo_;
property int foo {
get { return foo_; }
};
getter,setterの実装をどうするか考えた結果、採用(別に私のオリジナルではありません)したのが以下の方法です。
Class = function() { this._foo = 0; } //privateメンバーは'_'で始める
Class.prototype.foo = function (value) {
if(!arguments.length) {
return this._foo;
} else {
this._foo = value;
}
}
実用上これで問題ないですが、.Net Framework のPropertyGridやXmlSerializerを実装しようとすると機械的にgetter,setterの
有無を確認できる方が都合が良いです。かといって getFoo() 等にするのは嫌・・・。
で、あいだととってgetter,setterをプライベート相当で定義することにします。
Class.prototype.__foo = {}
Class.prototype.__foo.get = function() {
return this._foo;
}
Class.prototype.foo = function (value) {
if(!arguments.length) {
return this.__foo.get();
} else {
this.__foo.set(value); //エラー処理は割愛
}
}
まあ、これを一つ一つ書くのは面倒なので関数を用意します。
function __property__(object, name, get, set, def) {
var _nm = "_" + name;
var __nm = "__" + name;
object.prototype[_nm] = def || false;
object.prototype[__nm] = { 'get': get, 'set': set };
return function (value) {
if (!arguments.length) {
!this[__nm].get && throw new Error('has not getter');
return this[__nm].get.apply(this);
} else {
!this[__nm].set && throw new Error('has not setter');
this[__nm].set.apply(this, arguments);
}
};
}
Class.prototype.foo = __property__(
Class,
"foo",
function() { return this._foo; },
null ,
"hoge");
・・・やり過ぎかなorz